unofficial mirror of meta@public-inbox.org
 help / color / mirror / Atom feed
* [PATCH] tests: make require_git and require_cmd easier-to-use
@ 2023-01-30 22:50 Eric Wong
  0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2023-01-30 22:50 UTC (permalink / raw)
  To: meta

We'll rely on defined(wantarray) to implicitly skip subtests,
and memoize these to reduce syscalls, since tests should
be short-lived enough to not be affected by new installations or
removals of git/xapian-compact/curl/etc...
---
 lib/PublicInbox/TestCommon.pm | 38 +++++++++++++++++++----------------
 t/admin.t                     |  4 ++--
 t/config.t                    |  5 ++---
 t/convert-compact.t           |  5 ++---
 t/git.t                       |  5 +++--
 t/imapd.t                     |  5 ++---
 t/import.t                    |  9 +++++----
 t/index-git-times.t           |  5 ++---
 t/init.t                      |  8 ++++----
 t/nntpd.t                     |  2 +-
 t/v2mirror.t                  |  4 ++--
 xt/git-http-backend.t         |  8 +++-----
 xt/httpd-async-stream.t       |  8 ++++----
 xt/imapd-mbsync-oimap.t       |  9 +++++----
 xt/pop3d-mpop.t               |  8 ++++----
 15 files changed, 62 insertions(+), 61 deletions(-)

diff --git a/lib/PublicInbox/TestCommon.pm b/lib/PublicInbox/TestCommon.pm
index b36c71a6..1fe7931e 100644
--- a/lib/PublicInbox/TestCommon.pm
+++ b/lib/PublicInbox/TestCommon.pm
@@ -93,31 +93,35 @@ sub tcp_connect {
 }
 
 sub require_cmd ($;$) {
-	my ($cmd, $maybe) = @_;
+	my ($cmd, $nr) = @_;
 	require PublicInbox::Spawn;
-	my $bin = PublicInbox::Spawn::which($cmd);
+	state %CACHE;
+	my $bin = $CACHE{$cmd} //= PublicInbox::Spawn::which($cmd);
 	return $bin if $bin;
-	$maybe ? 0 : plan(skip_all => "$cmd missing from PATH for $0");
+	return plan(skip_all => "$cmd missing from PATH for $0") if !$nr;
+	defined(wantarray) ? undef : skip("$cmd missing, skipping $nr tests")
 }
 
-sub have_xapian_compact () {
-	require_cmd($ENV{XAPIAN_COMPACT} || 'xapian-compact', 1);
+sub have_xapian_compact (;$) {
+	require_cmd($ENV{XAPIAN_COMPACT} || 'xapian-compact', @_ ? $_[0] : ());
 }
 
 sub require_git ($;$) {
-	my ($req, $maybe) = @_;
-	my ($req_maj, $req_min, $req_sub) = split(/\./, $req);
-	my ($cur_maj, $cur_min, $cur_sub) = (xqx([qw(git --version)])
-			=~ /version (\d+)\.(\d+)(?:\.(\d+))?/);
+	my ($req, $nr) = @_;
+	state ($cur_int, $cur_ver);
+	$cur_int //= do {
+		chomp($cur_ver = xqx([qw(git --version)]));
+		my @v = ($cur_ver =~ /version (\d+)\.(\d+)(?:\.(\d+))?/);
+		($v[0] << 24) | ($v[1] << 16) | ($v[2] // 0);
+	};
 
+	my ($req_maj, $req_min, $req_sub) = split(/\./, $req);
 	my $req_int = ($req_maj << 24) | ($req_min << 16) | ($req_sub // 0);
-	my $cur_int = ($cur_maj << 24) | ($cur_min << 16) | ($cur_sub // 0);
-	if ($cur_int < $req_int) {
-		return 0 if $maybe;
-		plan skip_all =>
-			"git $req+ required, have $cur_maj.$cur_min.$cur_sub";
-	}
-	1;
+
+	return 1 if $cur_int >= $req_int;
+	return plan skip_all => "git $req+ required, have $cur_ver" if !$nr;
+	defined(wantarray) ? undef :
+		skip("git $req+ required (have $cur_ver), skipping $nr tests")
 }
 
 my %IPv6_VERSION = (
@@ -570,7 +574,7 @@ SKIP: {
 	my $test_opt = shift // {};
 	local $lei_cwdfh;
 	opendir $lei_cwdfh, '.' or xbail "opendir .: $!";
-	require_git(2.6, 1) or skip('git 2.6+ required for lei test', 2);
+	require_git(2.6, 1);
 	my $mods = $test_opt->{mods} // [ 'lei' ];
 	require_mods(@$mods, 2);
 
diff --git a/t/admin.t b/t/admin.t
index 8d09bfc1..20e3deb7 100644
--- a/t/admin.t
+++ b/t/admin.t
@@ -1,5 +1,5 @@
 #!perl -w
-# Copyright (C) 2019-2021 all contributors <meta@public-inbox.org>
+# Copyright (C) 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;
@@ -13,7 +13,7 @@ my ($res, $err, $v);
 my $v2ibx;
 SKIP: {
 	require_mods(qw(DBD::SQLite), 5);
-	require_git(2.6, 1) or skip 5, 'git too old';
+	require_git(2.6, 5);
 	$v2ibx = create_inbox 'v2', indexlevel => 'basic', version => 2,
 				-no_gc => 1, sub {
 		my ($v2w, $ibx) = @_;
diff --git a/t/config.t b/t/config.t
index 7e753cbe..ba83e63f 100644
--- a/t/config.t
+++ b/t/config.t
@@ -1,4 +1,4 @@
-# Copyright (C) 2014-2021 all contributors <meta@public-inbox.org>
+# Copyright (C) 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;
@@ -245,8 +245,7 @@ EOF
 
 SKIP: {
 	# XXX wildcard match requires git 2.26+
-	require_git('1.8.5', 2) or
-		skip 'git 1.8.5+ required for --url-match', 2;
+	require_git('1.8.5', 2);
 	my $f = "$tmpdir/urlmatch";
 	open my $fh, '>', $f or BAIL_OUT $!;
 	print $fh <<EOF or BAIL_OUT $!;
diff --git a/t/convert-compact.t b/t/convert-compact.t
index def09567..bad6560e 100644
--- a/t/convert-compact.t
+++ b/t/convert-compact.t
@@ -1,5 +1,5 @@
 #!perl -w
-# Copyright (C) 2018-2021 all contributors <meta@public-inbox.org>
+# Copyright (C) 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;
@@ -8,8 +8,7 @@ use PublicInbox::TestCommon;
 use PublicInbox::Import;
 require_git(2.6);
 require_mods(qw(DBD::SQLite Search::Xapian));
-have_xapian_compact or
-	plan skip_all => 'xapian-compact missing for '.__FILE__;
+have_xapian_compact;
 my ($tmpdir, $for_destroy) = tmpdir();
 my $ibx = create_inbox 'v1', indexlevel => 'medium', tmpdir => "$tmpdir/v1",
 		pre_cb => sub {
diff --git a/t/git.t b/t/git.t
index d8957e42..dfa5eab2 100644
--- a/t/git.t
+++ b/t/git.t
@@ -1,7 +1,8 @@
+#!perl -w
 # Copyright (C) all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 use strict;
-use Test::More;
+use v5.10.1;
 use PublicInbox::TestCommon;
 my ($dir, $for_destroy) = tmpdir();
 use PublicInbox::Import;
@@ -134,7 +135,7 @@ if (1) {
 }
 
 SKIP: {
-	require_git(2.6, 7) or skip('need git 2.6+ for --batch-all-objects', 7);
+	require_git(2.6, 7);
 	my ($alt, $alt_obj) = tmpdir();
 	my $hash_obj = [ 'git', "--git-dir=$alt", qw(hash-object -w --stdin) ];
 	PublicInbox::Import::init_bare($alt);
diff --git a/t/imapd.t b/t/imapd.t
index cbd6c1b9..c7dc01a5 100644
--- a/t/imapd.t
+++ b/t/imapd.t
@@ -3,7 +3,7 @@
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 # end-to-end IMAP tests, see unit tests in t/imap.t, too
 use strict;
-use Test::More;
+use v5.10.1;
 use Time::HiRes ();
 use PublicInbox::TestCommon;
 use PublicInbox::Config;
@@ -438,8 +438,7 @@ ok($mic->logout, 'logged out');
 
 SKIP: {
 	use_ok 'PublicInbox::InboxIdle';
-	require_git('1.8.5', 1) or
-		skip('git 1.8.5+ needed for --urlmatch', 4);
+	require_git '1.8.5', 4;
 	my $old_env = { HOME => $ENV{HOME} };
 	my $home = "$tmpdir/watch_home";
 	mkdir $home or BAIL_OUT $!;
diff --git a/t/import.t b/t/import.t
index 4ba74022..f1d61dae 100644
--- a/t/import.t
+++ b/t/import.t
@@ -1,8 +1,8 @@
+#!perl -w
 # Copyright (C) all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+use v5.10.1;
 use strict;
-use warnings;
-use Test::More;
 use PublicInbox::Eml;
 use PublicInbox::Smsg;
 use PublicInbox::Git;
@@ -26,10 +26,11 @@ hello world
 EOF
 
 my $v2 = require_git(2.6, 1);
-my $smsg = bless {}, 'PublicInbox::Smsg' if $v2;
+my $smsg = $v2 ? bless({}, 'PublicInbox::Smsg') : undef;
 like($im->add($mime, undef, $smsg), qr/\A:[0-9]+\z/, 'added one message');
 
-if ($v2) {
+SKIP: {
+	skip 'git 2.6+ required', 3 if !$v2;
 	like($smsg->{blob}, qr/\A[a-f0-9]{40,64}\z/, 'got last object_id');
 	my @cmd = ('git', "--git-dir=$git->{git_dir}", qw(hash-object --stdin));
 	open my $in, '+<', undef or BAIL_OUT "open(+<): $!";
diff --git a/t/index-git-times.t b/t/index-git-times.t
index 52173396..ffe9223c 100644
--- a/t/index-git-times.t
+++ b/t/index-git-times.t
@@ -1,9 +1,8 @@
 #!perl -w
-# Copyright (C) 2020-2021 all contributors <meta@public-inbox.org>
+# Copyright (C) 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 Test::More;
 use PublicInbox::TestCommon;
 use PublicInbox::Config;
 use PublicInbox::Admin;
@@ -74,7 +73,7 @@ my $smsg;
 	is($res->[0]->{ds}, $smsg->{ds}, 'Xapian search on datestamp');
 }
 SKIP: {
-	require_git(2.6, 1) or skip('git 2.6+ required for v2', 10);
+	require_git(2.6, 10);
 	my $v2dir = "$tmpdir/v2";
 	run_script(['-convert', $v1dir, $v2dir]) or die 'v2 conversion failed';
 
diff --git a/t/init.t b/t/init.t
index 460c83f3..46258e45 100644
--- a/t/init.t
+++ b/t/init.t
@@ -1,8 +1,8 @@
-# Copyright (C) 2014-2021 all contributors <meta@public-inbox.org>
+#!perl -w
+# Copyright (C) all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 use strict;
-use warnings;
-use Test::More;
+use v5.10.1;
 use PublicInbox::Config;
 use PublicInbox::TestCommon;
 use PublicInbox::Admin;
@@ -117,7 +117,7 @@ sub quiet_fail {
 
 SKIP: {
 	require_mods(qw(DBD::SQLite Search::Xapian), 2);
-	require_git(2.6, 1) or skip "git 2.6+ required", 2;
+	require_git(2.6, 2);
 	use_ok 'PublicInbox::Msgmap';
 	local $ENV{PI_DIR} = "$tmpdir/.public-inbox/";
 	local $ENV{PI_EMERGENCY} = "$tmpdir/.public-inbox/emergency";
diff --git a/t/nntpd.t b/t/nntpd.t
index 84a60574..dbbc37b8 100644
--- a/t/nntpd.t
+++ b/t/nntpd.t
@@ -413,7 +413,7 @@ sub test_watch {
 	use_ok 'PublicInbox::Watch';
 	use_ok 'PublicInbox::InboxIdle';
 	use_ok 'PublicInbox::Config';
-	require_git('1.8.5', 1) or skip('git 1.8.5+ needed for --urlmatch', 4);
+	require_git('1.8.5', 4);
 	my $old_env = { HOME => $ENV{HOME} };
 	my $home = "$tmpdir/watch_home";
 	mkdir $home or BAIL_OUT $!;
diff --git a/t/v2mirror.t b/t/v2mirror.t
index f9074e45..c1c66d45 100644
--- a/t/v2mirror.t
+++ b/t/v2mirror.t
@@ -1,4 +1,4 @@
-# Copyright (C) 2018-2021 all contributors <meta@public-inbox.org>
+# Copyright (C) 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;
@@ -330,7 +330,7 @@ SKIP: {
 	require_mods('Email::MIME', 1); # for legacy revision
 	# using plackup to test old PublicInbox::WWW since -httpd from
 	# back then relied on some packages we no longer depend on
-	my $plackup = which('plackup') or skip('no plackup in path', 1);
+	my $plackup = require_cmd('plackup', 1) or skip('no plackup in path', 1);
 	require PublicInbox::Lock;
 	chomp $oldrev;
 	my ($base) = ($0 =~ m!\b([^/]+)\.[^\.]+\z!);
diff --git a/xt/git-http-backend.t b/xt/git-http-backend.t
index 1f3ba063..d78fe79f 100644
--- a/xt/git-http-backend.t
+++ b/xt/git-http-backend.t
@@ -1,14 +1,13 @@
+#!perl -w
 # Copyright (C) all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 #
 # Ensure buffering behavior in -httpd doesn't cause runaway memory use
 # or data corruption
 use strict;
-use warnings;
-use Test::More;
+use v5.10.1;
 use POSIX qw(setsid);
 use PublicInbox::TestCommon;
-use PublicInbox::Spawn qw(which);
 
 my $git_dir = $ENV{GIANT_GIT_DIR};
 plan 'skip_all' => 'GIANT_GIT_DIR not defined' unless $git_dir;
@@ -77,8 +76,7 @@ SKIP: { # make sure Last-Modified + If-Modified-Since works with curl
 	my $nr = 6;
 	skip 'no description', $nr unless -f "$git_dir/description";
 	my $mtime = (stat(_))[9];
-	my $curl = which('curl');
-	skip 'curl(1) not found', $nr unless $curl;
+	my $curl = require_cmd('curl', 1) or skip 'curl(1) not found', $nr;
 	my $url = "http://$host:$port/description";
 	my $dst = "$tmpdir/desc";
 	is(xsys($curl, qw(-RsSf), '-o', $dst, $url), 0, 'curl -R');
diff --git a/xt/httpd-async-stream.t b/xt/httpd-async-stream.t
index c7039f3e..0658c691 100644
--- a/xt/httpd-async-stream.t
+++ b/xt/httpd-async-stream.t
@@ -1,17 +1,17 @@
 #!perl -w
-# Copyright (C) 2020-2021 all contributors <meta@public-inbox.org>
+# Copyright (C) all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 # Expensive test to validate compression and TLS.
 use strict;
-use Test::More;
+use v5.10.1;
 use PublicInbox::TestCommon;
 use PublicInbox::DS qw(now);
-use PublicInbox::Spawn qw(which popen_rd);
+use PublicInbox::Spawn qw(popen_rd);
 use Digest::MD5;
 use POSIX qw(_exit);
 my $inboxdir = $ENV{GIANT_INBOX_DIR};
 plan skip_all => "GIANT_INBOX_DIR not defined for $0" unless $inboxdir;
-my $curl = which('curl') or plan skip_all => "curl(1) missing for $0";
+my $curl = require_cmd('curl');
 my ($tmpdir, $for_destroy) = tmpdir();
 require_mods(qw(DBD::SQLite));
 my $JOBS = $ENV{TEST_JOBS} // 4;
diff --git a/xt/imapd-mbsync-oimap.t b/xt/imapd-mbsync-oimap.t
index 0baf5b4c..b0281105 100644
--- a/xt/imapd-mbsync-oimap.t
+++ b/xt/imapd-mbsync-oimap.t
@@ -1,12 +1,12 @@
 #!perl -w
-# Copyright (C) 2020-2021 all contributors <meta@public-inbox.org>
+# Copyright (C) all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 # ensure mbsync and offlineimap compatibility
 use strict;
 use v5.10.1;
 use File::Path qw(mkpath);
 use PublicInbox::TestCommon;
-use PublicInbox::Spawn qw(which spawn);
+use PublicInbox::Spawn qw(spawn);
 require_mods(qw(-imapd));
 my $inboxdir = $ENV{GIANT_INBOX_DIR};
 (defined($inboxdir) && -d $inboxdir) or
@@ -42,7 +42,8 @@ my %pids;
 
 SKIP: {
 	mkpath([map { "$tmpdir/oimapdir/$_" } qw(cur new tmp)]);
-	my $oimap = which('offlineimap') or skip 'no offlineimap(1)', 1;
+	my $oimap = require_cmd('offlineimap', 1) or
+		skip 'no offlineimap(1)', 1;
 	open my $fh, '>', "$tmpdir/.offlineimaprc" or BAIL_OUT "open: $!";
 	print $fh <<EOF or BAIL_OUT "print: $!";
 [general]
@@ -78,7 +79,7 @@ EOF
 
 SKIP: {
 	mkpath([map { "$tmpdir/mbsyncdir/test/$_" } qw(cur new tmp)]);
-	my $mbsync = which('mbsync') or skip 'no mbsync(1)', 1;
+	my $mbsync = require_cmd('mbsync', 1) or skip 'no mbsync(1)', 1;
 	open my $fh, '>', "$tmpdir/.mbsyncrc" or BAIL_OUT "open: $!";
 	print $fh <<EOF or BAIL_OUT "print: $!";
 Create Slave
diff --git a/xt/pop3d-mpop.t b/xt/pop3d-mpop.t
index 8648b953..fc82bc6b 100644
--- a/xt/pop3d-mpop.t
+++ b/xt/pop3d-mpop.t
@@ -5,12 +5,13 @@
 use v5.12;
 use File::Path qw(make_path);
 use PublicInbox::TestCommon;
-use PublicInbox::Spawn qw(which spawn);
+use PublicInbox::Spawn qw(spawn);
 my $inboxdir = $ENV{GIANT_INBOX_DIR};
 (defined($inboxdir) && -d $inboxdir) or
 	plan skip_all => "GIANT_INBOX_DIR not defined for $0";
 plan skip_all => "bad characters in $inboxdir" if $inboxdir =~ m![^\w\.\-/]!;
-my $uuidgen = which('uuidgen') or plan skip_all => 'uuidgen(1) missing';
+my $uuidgen = require_cmd('uuidgen');
+my $mpop = require_cmd('mpop');
 require_mods(qw(DBD::SQLite));
 require_git('2.6'); # for v2
 require_mods(qw(File::FcntlLock)) if $^O !~ /\A(?:linux|freebsd)\z/;
@@ -41,8 +42,7 @@ chomp(my $uuid = xqx([$uuidgen]));
 make_path("$tmpdir/home/.config/mpop",
 	map { "$tmpdir/md/$_" } qw(new cur tmp));
 
-SKIP: {
-	my $mpop = which('mpop') or skip('mpop(1) missing', 1);
+{
 	open my $fh, '>', "$tmpdir/home/.config/mpop/config"
 		or xbail "open $!";
 	chmod 0600, $fh;

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2023-01-30 22:50 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-30 22:50 [PATCH] tests: make require_git and require_cmd easier-to-use Eric Wong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).