git: a259b98fa211 - main - tests: skip gracefully when the tested binary's own package isn't installed

From: Warner Losh <imp_at_FreeBSD.org>
Date: Fri, 11 Sep 2026 05:51:32 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=a259b98fa211ed87bfee58c575de4e2de94ee0fa

commit a259b98fa211ed87bfee58c575de4e2de94ee0fa
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2026-09-11 05:42:25 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2026-09-11 05:42:25 +0000

    tests: skip gracefully when the tested binary's own package isn't installed
    
    pkgbase splits programs and their tests into separate packages (e.g.
    unifdef/yacc/indent/file2c -> toolchain, jail -> jail, etc), while their
    tests always land in the generic tests package.  Installing just the
    tests package therefore leaves these suites unable to find the binary
    they exercise, and they fail confusingly instead of skipping.
    
    Rather than force all packages to be installed for the tests package,
    make the tests cope with the missing packages.  Add require.progs (or,
    for TAP/PLAIN-style suites with no atf_set hook: TEST_METADATA
    required_programs) for the binary under test in: bectl, certctl,
    ctfconvert, dhclient, file2c, indent, ipfw, jail, lastcomm, mixer,
    newsyslog, nvmecontrol, pfctl, praudit, sa, syslogd, tunefs, unifdef,
    yacc, ztest.
    
    I skipped adding data for all the binaries in the base runtime
    package for simplicity.
    
    Assisted-by:            Claude Code (Sonnet 5)
    Sponsored by:           Netflix
    Reviewed by:            ngie
    Differential Revision:  https://reviews.freebsd.org/D58262
---
 cddl/usr.bin/ztest/tests/ztest.sh               |  1 +
 contrib/netbsd-tests/usr.bin/unifdef/t_basic.sh |  1 +
 sbin/bectl/tests/bectl_test.sh                  | 11 ++++++++++-
 sbin/dhclient/tests/pcp.sh                      |  2 ++
 sbin/ipfw/tests/ipfw_test.sh                    |  1 +
 sbin/nvmecontrol/tests/basic.sh                 | 10 ++++++++++
 sbin/pfctl/tests/macro.sh                       |  1 +
 sbin/pfctl/tests/pfctl_test.c                   |  4 ++++
 sbin/tunefs/tests/tunefs_test.sh                |  6 ++++++
 usr.bin/file2c/tests/Makefile                   |  1 +
 usr.bin/indent/tests/functional_test.sh         |  5 +++++
 usr.bin/lastcomm/tests/Makefile                 |  1 +
 usr.bin/unifdef/tests/unifdef_test.sh           |  3 +++
 usr.bin/yacc/tests/Makefile                     |  1 +
 usr.sbin/certctl/tests/certctl_test.sh          |  6 ++++++
 usr.sbin/jail/tests/jail_basic_test.sh          |  8 +++++++-
 usr.sbin/mixer/tests/mixer_test.sh              |  5 +++++
 usr.sbin/newsyslog/tests/Makefile               |  1 +
 usr.sbin/praudit/tests/praudit_test.sh          | 10 ++++++++++
 usr.sbin/sa/tests/Makefile                      |  1 +
 usr.sbin/syslogd/tests/syslogd_test.sh          | 16 ++++++++++++++++
 21 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/cddl/usr.bin/ztest/tests/ztest.sh b/cddl/usr.bin/ztest/tests/ztest.sh
index 8bc377917992..9f43307d18c9 100755
--- a/cddl/usr.bin/ztest/tests/ztest.sh
+++ b/cddl/usr.bin/ztest/tests/ztest.sh
@@ -7,6 +7,7 @@ ztest_head()
 	atf_set "descr" "Run ztest"
 	atf_set "timeout" 900
 	atf_set "require.config" "rt_long"
+	atf_set "require.progs" ztest
 }
 
 ztest_body()
diff --git a/contrib/netbsd-tests/usr.bin/unifdef/t_basic.sh b/contrib/netbsd-tests/usr.bin/unifdef/t_basic.sh
index 751c303075b8..17fe87bfb078 100755
--- a/contrib/netbsd-tests/usr.bin/unifdef/t_basic.sh
+++ b/contrib/netbsd-tests/usr.bin/unifdef/t_basic.sh
@@ -43,6 +43,7 @@ basic_body() {
 atf_test_case lastline
 lastline_head() {
 	atf_set "descr" "Checks with directive on last line (PR bin/47068)"
+	atf_set "require.progs" "unifdef"
 }
 
 lastline_body() {
diff --git a/sbin/bectl/tests/bectl_test.sh b/sbin/bectl/tests/bectl_test.sh
index 6aa94127aa36..e54e0664e07a 100755
--- a/sbin/bectl/tests/bectl_test.sh
+++ b/sbin/bectl/tests/bectl_test.sh
@@ -74,6 +74,7 @@ bectl_create_head()
 {
 	atf_set "descr" "Check the various forms of bectl create"
 	atf_set "require.user" root
+	atf_set "require.progs" bectl
 }
 bectl_create_body()
 {
@@ -145,6 +146,7 @@ bectl_destroy_head()
 {
 	atf_set "descr" "Check bectl destroy"
 	atf_set "require.user" root
+	atf_set "require.progs" bectl
 }
 bectl_destroy_body()
 {
@@ -233,6 +235,7 @@ bectl_export_import_head()
 {
 	atf_set "descr" "Check bectl export and import"
 	atf_set "require.user" root
+	atf_set "require.progs" bectl
 }
 bectl_export_import_body()
 {
@@ -269,6 +272,7 @@ bectl_list_head()
 {
 	atf_set "descr" "Check bectl list"
 	atf_set "require.user" root
+	atf_set "require.progs" bectl
 }
 bectl_list_body()
 {
@@ -312,6 +316,7 @@ bectl_mount_head()
 {
 	atf_set "descr" "Check bectl mount/unmount"
 	atf_set "require.user" root
+	atf_set "require.progs" bectl
 }
 bectl_mount_body()
 {
@@ -354,6 +359,7 @@ bectl_rename_head()
 {
 	atf_set "descr" "Check bectl rename"
 	atf_set "require.user" root
+	atf_set "require.progs" bectl
 }
 bectl_rename_body()
 {
@@ -388,7 +394,7 @@ bectl_jail_head()
 {
 	atf_set "descr" "Check bectl rename"
 	atf_set "require.user" root
-	atf_set "require.progs" jail
+	atf_set "require.progs" jail bectl
 }
 bectl_jail_body()
 {
@@ -504,6 +510,7 @@ bectl_promotion_head()
 {
 	atf_set "descr" "Check bectl promotion upon activation"
 	atf_set "require.user" root
+	atf_set "require.progs" bectl
 }
 bectl_promotion_body()
 {
@@ -557,6 +564,7 @@ bectl_destroy_bootonce_head()
 {
 	atf_set "descr" "Check bectl destroy (bootonce)"
 	atf_set "require.user" root
+	atf_set "require.progs" bectl
 }
 bectl_destroy_bootonce_body()
 {
@@ -601,6 +609,7 @@ bectl_rename_bootonce_head()
 {
 	atf_set "descr" "Check bectl destroy (bootonce)"
 	atf_set "require.user" root
+	atf_set "require.progs" bectl
 }
 bectl_rename_bootonce_body()
 {
diff --git a/sbin/dhclient/tests/pcp.sh b/sbin/dhclient/tests/pcp.sh
index 4875a10a10ce..8dcae7440eeb 100644
--- a/sbin/dhclient/tests/pcp.sh
+++ b/sbin/dhclient/tests/pcp.sh
@@ -53,6 +53,7 @@ normal_head()
 {
 	atf_set descr 'test dhclient against a server'
 	atf_set require.user root
+	atf_set "require.progs" dhclient
 }
 
 normal_body()
@@ -107,6 +108,7 @@ pcp_head()
 {
 	atf_set descr 'test dhclient on pcp interface'
 	atf_set require.user root
+	atf_set "require.progs" dhclient
 }
 
 pcp_body()
diff --git a/sbin/ipfw/tests/ipfw_test.sh b/sbin/ipfw/tests/ipfw_test.sh
index c7993c430a3d..8b003acc203e 100644
--- a/sbin/ipfw/tests/ipfw_test.sh
+++ b/sbin/ipfw/tests/ipfw_test.sh
@@ -12,6 +12,7 @@ nptv6_head()
 	atf_set "descr" "Test creation of NPTv6 rules"
 	atf_set "require.user" "root"
 	atf_set "require.kmods" "ipfw_nptv6"
+	atf_set "require.progs" ipfw
 }
 nptv6_body()
 {
diff --git a/sbin/nvmecontrol/tests/basic.sh b/sbin/nvmecontrol/tests/basic.sh
index 83b74721c66b..00043b9ad7d8 100755
--- a/sbin/nvmecontrol/tests/basic.sh
+++ b/sbin/nvmecontrol/tests/basic.sh
@@ -44,6 +44,7 @@ fake_lib_head()
 {
 	atf_set "descr" "check loading of a library from /lib"
 	atf_set "require.user" "root"
+	atf_set "require.progs" nvmecontrol
 }
 fake_lib_body()
 {
@@ -67,6 +68,7 @@ fake_local_lib_head()
 {
 	atf_set "descr" "check loading of a library from /usr/local/lib"
 	atf_set "require.user" "root"
+	atf_set "require.progs" nvmecontrol
 }
 fake_local_lib_body()
 {
@@ -90,6 +92,7 @@ admin_passthru_head()
 {
 	atf_set "descr" "check the admin-passthru command"
 	atf_set "require.user" "root"
+	atf_set "require.progs" nvmecontrol
 }
 admin_passthru_body()
 {
@@ -106,6 +109,7 @@ devlist_head()
 {
 	atf_set "descr" "check the devlist command"
 	atf_set "require.user" "root"
+	atf_set "require.progs" nvmecontrol
 }
 devlist_body()
 {
@@ -122,6 +126,7 @@ identify_head()
 {
 	atf_set "descr" "check the identify command"
 	atf_set "require.user" "root"
+	atf_set "require.progs" nvmecontrol
 }
 identify_body()
 {
@@ -138,6 +143,7 @@ io_passthru_head()
 {
 	atf_set "descr" "check the io-passthru command"
 	atf_set "require.user" "root"
+	atf_set "require.progs" nvmecontrol
 }
 io_passthru_body()
 {
@@ -154,6 +160,7 @@ logpage_head()
 {
 	atf_set "descr" "check the logpage command"
 	atf_set "require.user" "root"
+	atf_set "require.progs" nvmecontrol
 }
 logpage_body()
 {
@@ -170,6 +177,7 @@ nsid_head()
 {
 	atf_set "descr" "check the nsid command"
 	atf_set "require.user" "root"
+	atf_set "require.progs" nvmecontrol
 }
 nsid_body()
 {
@@ -186,6 +194,7 @@ power_head()
 {
 	atf_set "descr" "check the power command"
 	atf_set "require.user" "root"
+	atf_set "require.progs" nvmecontrol
 }
 power_body()
 {
@@ -202,6 +211,7 @@ reset_head()
 {
 	atf_set "descr" "check the reset command"
 	atf_set "require.user" "root"
+	atf_set "require.progs" nvmecontrol
 }
 reset_body()
 {
diff --git a/sbin/pfctl/tests/macro.sh b/sbin/pfctl/tests/macro.sh
index 071c6cb4f426..af50d92e0b60 100755
--- a/sbin/pfctl/tests/macro.sh
+++ b/sbin/pfctl/tests/macro.sh
@@ -4,6 +4,7 @@ space_head()
 {
 	atf_set descr "Test macros with spaces"
 	atf_set require.kmods "pf"
+	atf_set require.progs "pfctl"
 }
 
 space_body()
diff --git a/sbin/pfctl/tests/pfctl_test.c b/sbin/pfctl/tests/pfctl_test.c
index 5f0aa7826bb4..56605d33361d 100644
--- a/sbin/pfctl/tests/pfctl_test.c
+++ b/sbin/pfctl/tests/pfctl_test.c
@@ -272,6 +272,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
 	{							\
 		atf_tc_set_md_var(tc, "descr", descr);		\
 		atf_tc_set_md_var(tc, "require.kmods", "pf");	\
+		atf_tc_set_md_var(tc, "require.progs", "pfctl");	\
 	}							\
 	ATF_TC_BODY(pf##number, tc)				\
 	{							\
@@ -282,6 +283,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
 	{							\
 		atf_tc_set_md_var(tc, "descr", "Self " descr);	\
 		atf_tc_set_md_var(tc, "require.kmods", "pf");	\
+		atf_tc_set_md_var(tc, "require.progs", "pfctl");	\
 	}							\
 	ATF_TC_BODY(selfpf##number, tc)				\
 	{							\
@@ -294,6 +296,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
 	{							\
 		atf_tc_set_md_var(tc, "descr", descr);		\
 		atf_tc_set_md_var(tc, "require.kmods", "pf");	\
+		atf_tc_set_md_var(tc, "require.progs", "pfctl");	\
 	}							\
 	ATF_TC_BODY(pf##number, tc)				\
 	{							\
@@ -308,6 +311,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
 		atf_tc_set_md_var(tc, "execenv", "jail");	\
 		atf_tc_set_md_var(tc, "execenv.jail.params", "vnet");	\
 		atf_tc_set_md_var(tc, "require.kmods", "pf");	\
+		atf_tc_set_md_var(tc, "require.progs", "pfctl");	\
 	}							\
 	ATF_TC_BODY(pf##number, tc)				\
 	{							\
diff --git a/sbin/tunefs/tests/tunefs_test.sh b/sbin/tunefs/tests/tunefs_test.sh
index 5df8dca1137e..dc99aa2140a1 100755
--- a/sbin/tunefs/tests/tunefs_test.sh
+++ b/sbin/tunefs/tests/tunefs_test.sh
@@ -64,6 +64,7 @@ posixacl_head()
 {
 	atf_set descr "Turn POSIX.1e ACLs on and off"
 	atf_set require.user "root"
+	atf_set "require.progs" tunefs
 }
 posixacl_body()
 {
@@ -81,6 +82,7 @@ nfs4acl_head()
 {
 	atf_set descr "Turn NFSv4 ACLs on and off"
 	atf_set require.user "root"
+	atf_set "require.progs" tunefs
 }
 nfs4acl_body()
 {
@@ -98,6 +100,7 @@ sunoj_head()
 {
 	atf_set descr "Turn Soft Updates on and off"
 	atf_set require.user "root"
+	atf_set "require.progs" tunefs
 }
 sunoj_body()
 {
@@ -115,6 +118,7 @@ suj_head()
 {
 	atf_set descr "Turn Soft Updates journaling on and off"
 	atf_set require.user "root"
+	atf_set "require.progs" tunefs
 }
 suj_body()
 {
@@ -132,6 +136,7 @@ gjournal_head()
 {
 	atf_set descr "Turn GEOM journaling on and off"
 	atf_set require.user "root"
+	atf_set "require.progs" tunefs
 }
 gjournal_body()
 {
@@ -149,6 +154,7 @@ conflict_head()
 {
 	atf_set descr "Soft Updates and GEOM journaling are mutually exclusive"
 	atf_set require.user "root"
+	atf_set "require.progs" tunefs
 }
 conflict_body()
 {
diff --git a/usr.bin/file2c/tests/Makefile b/usr.bin/file2c/tests/Makefile
index f54e3c5cf275..79b666eb6f16 100644
--- a/usr.bin/file2c/tests/Makefile
+++ b/usr.bin/file2c/tests/Makefile
@@ -1,6 +1,7 @@
 PACKAGE=	tests
 
 TAP_TESTS_SH=	legacy_test
+TEST_METADATA.legacy_test+=	required_programs="file2c"
 
 ${PACKAGE}FILES+=		regress.1.out
 ${PACKAGE}FILES+=		regress.2.out
diff --git a/usr.bin/indent/tests/functional_test.sh b/usr.bin/indent/tests/functional_test.sh
index 9cfe5878f69d..ffe201cf0a1c 100755
--- a/usr.bin/indent/tests/functional_test.sh
+++ b/usr.bin/indent/tests/functional_test.sh
@@ -53,11 +53,16 @@ add_legacy_testcase()
 	local tc=${1}
 
 	atf_test_case ${tc%.[0-9]}
+	eval "${tc%.[0-9]}_head() { atf_set \"require.progs\" indent; }"
 	eval "${tc%.[0-9]}_body() { check ${tc}; }"
 	atf_add_test_case ${tc%.[0-9]}
 }
 
 atf_test_case backup_suffix
+backup_suffix_head()
+{
+	atf_set "require.progs" indent
+}
 backup_suffix_body()
 {
 	local argmax=$(sysctl -n kern.argmax)
diff --git a/usr.bin/lastcomm/tests/Makefile b/usr.bin/lastcomm/tests/Makefile
index 8a00382979b1..d482ee0a1c4f 100644
--- a/usr.bin/lastcomm/tests/Makefile
+++ b/usr.bin/lastcomm/tests/Makefile
@@ -2,6 +2,7 @@ PACKAGE=	tests
 
 TAP_TESTS_SH=	legacy_test
 TEST_METADATA.legacy_test+=	allowed_architectures="amd64 i386"
+TEST_METADATA.legacy_test+=	required_programs="lastcomm"
 
 ${PACKAGE}FILES+=		v1-amd64-acct.in
 ${PACKAGE}FILES+=		v1-amd64.out
diff --git a/usr.bin/unifdef/tests/unifdef_test.sh b/usr.bin/unifdef/tests/unifdef_test.sh
index 7af782e8c9e2..181bc30c6d4e 100644
--- a/usr.bin/unifdef/tests/unifdef_test.sh
+++ b/usr.bin/unifdef/tests/unifdef_test.sh
@@ -7,6 +7,7 @@
 atf_test_case hash_comment
 hash_comment_head() {
 	atf_set descr "multiline comment follows directive"
+	atf_set "require.progs" unifdef
 }
 hash_comment_body() {
 	cat >f <<EOF
@@ -21,6 +22,7 @@ EOF
 atf_test_case redefine
 redefine_head() {
 	atf_set descr "redefine the same symbol"
+	atf_set "require.progs" unifdef
 }
 redefine_body() {
 	cat >file <<EOF
@@ -41,6 +43,7 @@ EOF
 atf_test_case sDU
 sDU_head() {
 	atf_set descr "simultaneous use of -s and -D or -U"
+	atf_set "require.progs" unifdef
 }
 sDU_body() {
 	atf_check unifdef -s -DFOO -UFOO /dev/null
diff --git a/usr.bin/yacc/tests/Makefile b/usr.bin/yacc/tests/Makefile
index c2832bc06853..93e90e14aba5 100644
--- a/usr.bin/yacc/tests/Makefile
+++ b/usr.bin/yacc/tests/Makefile
@@ -9,6 +9,7 @@ PLAIN_TESTS_SH=	yacc_tests
 # with root, this must be run as a non-privileged user; otherwise
 # the testcases will fail unexpectedly.
 TEST_METADATA.yacc_tests+=	required_user="unprivileged"
+TEST_METADATA.yacc_tests+=	required_programs="yacc"
 
 SCRIPTS=	run_test
 SCRIPTSDIR=	${TESTSDIR}
diff --git a/usr.sbin/certctl/tests/certctl_test.sh b/usr.sbin/certctl/tests/certctl_test.sh
index 133d65854c42..784d3a93c1f0 100644
--- a/usr.sbin/certctl/tests/certctl_test.sh
+++ b/usr.sbin/certctl/tests/certctl_test.sh
@@ -181,6 +181,7 @@ atf_test_case rehash
 rehash_head()
 {
 	atf_set "descr" "Test the rehash command"
+	atf_set "require.progs" certctl
 }
 rehash_body()
 {
@@ -218,6 +219,7 @@ atf_test_case list
 list_head()
 {
 	atf_set "descr" "Test the list and untrusted commands"
+	atf_set "require.progs" certctl
 }
 list_body()
 {
@@ -243,6 +245,7 @@ atf_test_case trust
 trust_head()
 {
 	atf_set "descr" "Test the trust command"
+	atf_set "require.progs" certctl
 }
 trust_body()
 {
@@ -262,6 +265,7 @@ atf_test_case untrust
 untrust_head()
 {
 	atf_set "descr" "Test the untrust command"
+	atf_set "require.progs" certctl
 }
 untrust_body()
 {
@@ -281,6 +285,7 @@ atf_test_case metalog
 metalog_head()
 {
 	atf_set "descr" "Verify the metalog"
+	atf_set "require.progs" certctl
 }
 metalog_body()
 {
@@ -312,6 +317,7 @@ atf_test_case misc
 misc_head()
 {
 	atf_set "descr" "Test miscellaneous edge cases"
+	atf_set "require.progs" certctl
 }
 misc_body()
 {
diff --git a/usr.sbin/jail/tests/jail_basic_test.sh b/usr.sbin/jail/tests/jail_basic_test.sh
index c662e44f1a16..93cd42ec90ba 100755
--- a/usr.sbin/jail/tests/jail_basic_test.sh
+++ b/usr.sbin/jail/tests/jail_basic_test.sh
@@ -29,6 +29,7 @@ basic_head()
 {
 	atf_set descr 'Basic jail test'
 	atf_set require.user root
+	atf_set require.progs jail
 }
 
 basic_body()
@@ -63,6 +64,7 @@ list_head()
 {
 	atf_set descr 'Specify some jail parameters as lists'
 	atf_set require.user root
+	atf_set require.progs jail
 }
 
 list_body()
@@ -92,6 +94,7 @@ nested_head()
 {
 	atf_set descr 'Hierarchical jails test'
 	atf_set require.user root
+	atf_set require.progs jail
 }
 
 nested_body()
@@ -132,6 +135,7 @@ commands_head()
 {
 	atf_set descr 'Commands jail test'
 	atf_set require.user root
+	atf_set require.progs jail
 }
 
 commands_body()
@@ -173,6 +177,7 @@ jid_name_set_head()
 {
 	atf_set descr 'Test that one can set both the jid and name in a config file'
 	atf_set require.user root
+	atf_set require.progs jail
 }
 
 find_unused_jid()
@@ -245,6 +250,7 @@ param_consistency_head()
 {
 	atf_set descr 'Test for consistency in jid/name params being set implicitly'
 	atf_set require.user root
+	atf_set require.progs jail
 }
 
 param_consistency_body()
@@ -315,7 +321,7 @@ setaudit_head()
 {
 	atf_set descr 'Test that setaudit works in a jail when configured with allow.setaudit'
 	atf_set require.user root
-	atf_set require.progs setaudit
+	atf_set require.progs setaudit jail
 }
 
 setaudit_body()
diff --git a/usr.sbin/mixer/tests/mixer_test.sh b/usr.sbin/mixer/tests/mixer_test.sh
index da5f4d7566bc..1fad53e3cbd5 100755
--- a/usr.sbin/mixer/tests/mixer_test.sh
+++ b/usr.sbin/mixer/tests/mixer_test.sh
@@ -68,6 +68,7 @@ o_flag_head()
 {
 	atf_set "descr" "Verify that the output of the -o flag can be used " \
 		"as valid input"
+	atf_set "require.progs" mixer
 }
 o_flag_body()
 {
@@ -85,6 +86,7 @@ atf_test_case d_flag cleanup
 d_flag_head()
 {
 	atf_set "descr" "Test default unit setting"
+	atf_set "require.progs" mixer
 }
 d_flag_body()
 {
@@ -106,6 +108,7 @@ atf_test_case volume cleanup
 volume_head()
 {
 	atf_set "descr" "Test volume setting"
+	atf_set "require.progs" mixer
 }
 volume_body()
 {
@@ -191,6 +194,7 @@ atf_test_case mute cleanup
 mute_head()
 {
 	atf_set "descr" "Test muting"
+	atf_set "require.progs" mixer
 }
 mute_body()
 {
@@ -224,6 +228,7 @@ atf_test_case recsrc cleanup
 recsrc_head()
 {
 	atf_set "descr" "Test recording source handling"
+	atf_set "require.progs" mixer
 }
 recsrc_body()
 {
diff --git a/usr.sbin/newsyslog/tests/Makefile b/usr.sbin/newsyslog/tests/Makefile
index 6c282f8f58b9..b5215d9467e5 100644
--- a/usr.sbin/newsyslog/tests/Makefile
+++ b/usr.sbin/newsyslog/tests/Makefile
@@ -1,3 +1,4 @@
 TAP_TESTS_SH=	legacy_test
+TEST_METADATA.legacy_test+=	required_programs="newsyslog"
 
 .include <bsd.test.mk>
diff --git a/usr.sbin/praudit/tests/praudit_test.sh b/usr.sbin/praudit/tests/praudit_test.sh
index 4aa98f0aa138..e56b4a1e9427 100644
--- a/usr.sbin/praudit/tests/praudit_test.sh
+++ b/usr.sbin/praudit/tests/praudit_test.sh
@@ -29,6 +29,7 @@ atf_test_case praudit_delim_comma
 praudit_delim_comma_head()
 {
 	atf_set "descr" "Verify that comma delimiter is present with -d ',' cmd"
+	atf_set "require.progs" praudit
 }
 
 praudit_delim_comma_body()
@@ -42,6 +43,7 @@ atf_test_case praudit_delim_underscore
 praudit_delim_underscore_head()
 {
 	atf_set "descr" "Verify that underscore delimiter is present with -d _"
+	atf_set "require.progs" praudit
 }
 
 praudit_delim_underscore_body()
@@ -56,6 +58,7 @@ praudit_no_args_head()
 {
 	atf_set "descr" "Verify that praudit outputs default form without " \
 			"any arguments"
+	atf_set "require.progs" praudit
 }
 
 praudit_no_args_body()
@@ -70,6 +73,7 @@ praudit_numeric_form_head()
 {
 	atf_set "descr" "Verify that praudit outputs the numeric form " \
 			"with -n flag"
+	atf_set "require.progs" praudit
 }
 
 praudit_numeric_form_body()
@@ -83,6 +87,7 @@ atf_test_case praudit_raw_form
 praudit_raw_form_head()
 {
 	atf_set "descr" "Verify that praudit outputs the raw form with -r flag"
+	atf_set "require.progs" praudit
 }
 
 praudit_raw_form_body()
@@ -97,6 +102,7 @@ praudit_same_line_head()
 {
 	atf_set "descr" "Verify that praudit outputs the trail in the same " \
 			"line  with -l flag"
+	atf_set "require.progs" praudit
 }
 
 praudit_same_line_body()
@@ -111,6 +117,7 @@ praudit_short_form_head()
 {
 	atf_set "descr" "Verify that praudit outputs the short form " \
 			"with -s flag"
+	atf_set "require.progs" praudit
 }
 
 praudit_short_form_body()
@@ -124,6 +131,7 @@ atf_test_case praudit_xml_form
 praudit_xml_form_head()
 {
 	atf_set "descr" "Verify that praudit outputs the XML file with -x flag"
+	atf_set "require.progs" praudit
 }
 
 praudit_xml_form_body()
@@ -139,6 +147,7 @@ praudit_sync_to_next_record_head()
 	atf_set "descr" "Verify that praudit(1) outputs the last few audit " \
 			"records when the initial part of the trail is " \
 			"corrputed."
+	atf_set "require.progs" praudit
 }
 
 praudit_sync_to_next_record_body()
@@ -158,6 +167,7 @@ praudit_raw_short_exclusive_head()
 {
 	atf_set "descr" "Verify that praudit outputs usage message on stderr " \
 			"when both raw and short options are specified"
+	atf_set "require.progs" praudit
 }
 
 praudit_raw_short_exclusive_body()
diff --git a/usr.sbin/sa/tests/Makefile b/usr.sbin/sa/tests/Makefile
index b10191a2e466..61a913fbc782 100644
--- a/usr.sbin/sa/tests/Makefile
+++ b/usr.sbin/sa/tests/Makefile
@@ -2,6 +2,7 @@ PACKAGE=	tests
 
 TAP_TESTS_SH=	legacy_test
 TEST_METADATA.legacy_test+=	allowed_architectures="amd64 i386"
+TEST_METADATA.legacy_test+=	required_programs="sa"
 
 ${PACKAGE}FILES+=		v1-amd64-sav.in
 ${PACKAGE}FILES+=		v1-amd64-sav.out
diff --git a/usr.sbin/syslogd/tests/syslogd_test.sh b/usr.sbin/syslogd/tests/syslogd_test.sh
index 0fba9b910a17..fe97f60c2684 100644
--- a/usr.sbin/syslogd/tests/syslogd_test.sh
+++ b/usr.sbin/syslogd/tests/syslogd_test.sh
@@ -20,6 +20,7 @@ atf_test_case "unix" "cleanup"
 unix_head()
 {
     atf_set descr "Messages are logged over UNIX transport"
+    atf_set "require.progs" syslogd
 }
 unix_body()
 {
@@ -39,6 +40,7 @@ atf_test_case "inet" "cleanup"
 inet_head()
 {
     atf_set descr "Messages are logged over INET transport"
+    atf_set "require.progs" syslogd
 }
 inet_body()
 {
@@ -62,6 +64,7 @@ atf_test_case "inet6" "cleanup"
 inet6_head()
 {
     atf_set descr "Messages are logged over INET6 transport"
+    atf_set "require.progs" syslogd
 }
 inet6_body()
 {
@@ -85,6 +88,7 @@ atf_test_case "reload" "cleanup"
 reload_head()
 {
     atf_set descr "SIGHUP correctly refreshes configuration"
+    atf_set "require.progs" syslogd
 }
 reload_body()
 {
@@ -116,6 +120,7 @@ atf_test_case "prog_filter" "cleanup"
 prog_filter_head()
 {
     atf_set descr "Messages are only received from programs in the filter"
+    atf_set "require.progs" syslogd
 }
 prog_filter_body()
 {
@@ -159,6 +164,7 @@ atf_test_case "host_filter" "cleanup"
 host_filter_head()
 {
     atf_set descr "Messages are only received from hostnames in the filter"
+    atf_set "require.progs" syslogd
 }
 host_filter_body()
 {
@@ -198,6 +204,7 @@ atf_test_case "prop_filter" "cleanup"
 prop_filter_head()
 {
     atf_set descr "Messages are received based on conditions in the propery based filter"
+    atf_set "require.progs" syslogd
 }
 prop_filter_body()
 {
@@ -270,6 +277,7 @@ atf_test_case "host_action" "cleanup"
 host_action_head()
 {
     atf_set descr "Sends a message to a specified host"
+    atf_set "require.progs" syslogd
 }
 host_action_body()
 {
@@ -307,6 +315,7 @@ atf_test_case "pipe_action" "cleanup"
 pipe_action_head()
 {
     atf_set descr "The pipe action evaluates provided command in sh(1)"
+    atf_set "require.progs" syslogd
 }
 pipe_action_body()
 {
@@ -331,6 +340,7 @@ atf_test_case "pipe_action_reload" "cleanup"
 pipe_action_reload_head()
 {
     atf_set descr "Pipe processes terminate gracefully on reload"
+    atf_set "require.progs" syslogd
 }
 pipe_action_reload_body()
 {
@@ -372,6 +382,7 @@ jail_noinet_head()
 {
     atf_set descr "syslogd -ss can be run in a jail without INET support"
     atf_set require.user root
+    atf_set "require.progs" syslogd
 }
 jail_noinet_body()
 {
@@ -423,6 +434,7 @@ allowed_peer_head()
 {
     atf_set descr "syslogd -a works"
     atf_set require.user root
+    atf_set "require.progs" syslogd
 }
 allowed_peer_body()
 {
@@ -470,6 +482,7 @@ allowed_peer_forwarding_head()
 {
     atf_set descr "syslogd forwards messages from its listening port"
     atf_set require.user root
+    atf_set "require.progs" syslogd
 }
 allowed_peer_forwarding_body()
 {
@@ -503,6 +516,7 @@ allowed_peer_wildcard_head()
 {
     atf_set descr "syslogd -a works with port wildcards"
     atf_set require.user root
+    atf_set "require.progs" syslogd
 }
 allowed_peer_wildcard_body()
 {
@@ -541,6 +555,7 @@ forward_head()
 {
     atf_set descr "syslogd forwards messages to a remote host"
     atf_set require.user root
+    atf_set "require.progs" syslogd
 }
 forward_body()
 {
@@ -600,6 +615,7 @@ forward_reload_head()
 {
     atf_set descr "syslogd might start before routes are configured"
     atf_set require.user root
+    atf_set "require.progs" syslogd
 }
 forward_reload_body()
 {