diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 21:06:40 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 21:06:40 +0000 |
commit | d827c6cf1631209f5042a9d1d8a7ecc24223c8a0 (patch) | |
tree | 91a431d301efd0e524bdfb0c46e97d591a9d7b03 /t | |
parent | Initial commit. (diff) | |
download | debhelper-upstream.tar.xz debhelper-upstream.zip |
Adding upstream version 13.11.4.upstream/13.11.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
88 files changed, 4044 insertions, 0 deletions
diff --git a/t/Dh_Lib/00-use.t b/t/Dh_Lib/00-use.t new file mode 100755 index 0000000..dc8a966 --- /dev/null +++ b/t/Dh_Lib/00-use.t @@ -0,0 +1,20 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Cwd; +use Test::More tests => 2; + +use File::Temp qw(tempdir); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); + +my $test_dir = tempdir(CLEANUP => 1); + +chdir($test_dir); + +# Packages that need to be able to (at least) load without requring +# d/control or d/compat. + +use_ok('Debian::Debhelper::Dh_Lib', '!dirname'); +use_ok('Debian::Debhelper::Buildsystem'); diff --git a/t/Dh_Lib/control-parsing.t b/t/Dh_Lib/control-parsing.t new file mode 100755 index 0000000..0658256 --- /dev/null +++ b/t/Dh_Lib/control-parsing.t @@ -0,0 +1,36 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More; + +use Cwd qw(abs_path); +use File::Basename qw(dirname); + +BEGIN { + my $dir = dirname(abs_path(__FILE__)); + unshift(@INC, dirname($dir)); + chdir($dir) or error("chdir($dir) failed: $!"); +}; + +use Test::DH; + +use Debian::Debhelper::Dh_Lib qw(!dirname); + +plan(tests => 10); + +is_deeply([getpackages()], [qw(foo-any foo-all)], 'packages list correct and in order'); +is_deeply([getpackages('both')], [qw(foo-any foo-all)], 'packages list correct and in order'); +is_deeply([getpackages('arch')], [qw(foo-any)], 'arch:linux-any'); +is_deeply([getpackages('indep')], [qw(foo-all)], 'arch:all'); + + +is(package_section('foo-any'), 'devel', 'binary section'); +is(package_section('foo-all'), 'misc', 'binary section (inherit from source)'); + + +is(package_declared_arch('foo-any'), 'linux-any', 'binary architecture (linux-any'); +is(package_declared_arch('foo-all'), 'all', 'binary architecture (all)'); + +ok(! package_is_arch_all('foo-any'), 'foo-any is not arch:all'); +ok(package_is_arch_all('foo-all'), 'foo-all is arch:all'); diff --git a/t/Dh_Lib/debian/changelog b/t/Dh_Lib/debian/changelog new file mode 100644 index 0000000..5850f0e --- /dev/null +++ b/t/Dh_Lib/debian/changelog @@ -0,0 +1,5 @@ +foo (1.0-1) unstable; urgency=low + + * Initial release. (Closes: #XXXXXX) + + -- Test <testing@nowhere> Mon, 11 Jul 2016 18:10:59 +0200 diff --git a/t/Dh_Lib/debian/control b/t/Dh_Lib/debian/control new file mode 100644 index 0000000..b1f0aa3 --- /dev/null +++ b/t/Dh_Lib/debian/control @@ -0,0 +1,19 @@ +# Comment before the source field + +Source: foo +Section: misc +Priority: optional +Maintainer: Test <testing@nowhere> +Standards-Version: 3.9.8 + +Package: foo-any +Section: devel +Architecture: linux-any +Description: package foo-any + Package foo-any + +Package: foo-all +Architecture: all +Description: package foo-all + Package foo-all + diff --git a/t/Dh_Lib/path.t b/t/Dh_Lib/path.t new file mode 100755 index 0000000..e5f9061 --- /dev/null +++ b/t/Dh_Lib/path.t @@ -0,0 +1,26 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More; + +use Cwd qw(abs_path); +use File::Basename qw(dirname); +use File::Temp qw(tempdir); + +BEGIN { + my $dir = dirname(abs_path(__FILE__)); + unshift(@INC, dirname($dir)); + chdir($dir) or error("chdir($dir) failed: $!"); +}; + +use Test::DH; +use Debian::Debhelper::Dh_Lib qw(!dirname); + +plan(tests => 3); + +ok(!is_empty_dir(__FILE__), "is_empty_dir(file) is false"); +ok(!is_empty_dir(dirname(__FILE__)), "is_empty_dir(non-empty) is false"); + +my $tempdir = tempdir(CLEANUP => 1); +ok(is_empty_dir($tempdir), "is_empty_dir(new-temp-dir) is true"); diff --git a/t/Test/DH.pm b/t/Test/DH.pm new file mode 100644 index 0000000..8d9e71f --- /dev/null +++ b/t/Test/DH.pm @@ -0,0 +1,212 @@ +package Test::DH; + +use strict; +use warnings; + +use Test::More; + +use Cwd qw(getcwd realpath); +use Errno qw(EEXIST); +use Exporter qw(import); + +use File::Temp qw(tempdir); +use File::Path qw(remove_tree make_path); +use File::Basename qw(dirname); + +our $ROOT_DIR; + +BEGIN { + my $res = realpath(__FILE__) or die('Cannot resolve ' . __FILE__ . ": $!"); + $ROOT_DIR = dirname(dirname(dirname($res))); +}; + +use lib "$ROOT_DIR/lib"; + +# These should be done before Dh_lib is loaded. +BEGIN { + $ENV{PATH} = "$ROOT_DIR:$ENV{PATH}" if $ENV{PATH} !~ m{\Q$ROOT_DIR\E/?:}; + $ENV{PERL5LIB} = join(':', "${ROOT_DIR}/lib", (grep {defined} $ENV{PERL5LIB})) + if not $ENV{PERL5LIB} or $ENV{PERL5LIB} !~ m{\Q$ROOT_DIR\E(?:/lib)?/?:}; + $ENV{DH_DATAFILES} = "${ROOT_DIR}/t/fixtures:${ROOT_DIR}"; + # Nothing in the tests requires root. + $ENV{DEB_RULES_REQUIRES_ROOT} = 'no'; + # Disable colors for good measure + $ENV{DH_COLORS} = 'never'; + $ENV{DPKG_COLORS} = 'never'; + + # Drop DEB_BUILD_PROFILES and DEB_BUILD_OPTIONS so they don't interfere + delete($ENV{DEB_BUILD_PROFILES}); + delete($ENV{DEB_BUILD_OPTIONS}); +}; + +use Debian::Debhelper::Dh_Lib qw(!dirname); + +our @EXPORT = qw( + each_compat_up_to_and_incl_subtest each_compat_subtest + each_compat_from_and_above_subtest run_dh_tool + create_empty_file readlines copy_file + error find_script non_deprecated_compat_levels + each_compat_from_x_to_and_incl_y_subtest +); + +our ($TEST_DH_COMPAT); + +my $START_DIR = getcwd(); +my $TEST_DIR; + + +sub copy_file { + my ($src, $dest, $mode) = @_; + $mode //= 0644; + return Debian::Debhelper::Dh_Lib::_install_file_to_path($mode, $src, $dest); +} + +sub run_dh_tool { + my (@cmd) = @_; + my $compat = $TEST_DH_COMPAT; + my $options = ref($cmd[0]) ? shift(@cmd) : {}; + my $pid; + + $pid = fork() // BAIL_OUT("fork failed: $!"); + if (not $pid) { + $ENV{DH_COMPAT} = $compat; + $ENV{DH_INTERNAL_TESTSUITE_SILENT_WARNINGS} = 1; + if (defined(my $env = $options->{env})) { + for my $k (sort(keys(%{$env}))) { + if (defined($env->{$k})) { + $ENV{$k} = $env->{$k}; + } else { + delete($ENV{$k}); + } + } + } + if ($options->{quiet}) { + open(STDOUT, '>', '/dev/null') or error("Reopen stdout: $!"); + open(STDERR, '>', '/dev/null') or error("Reopen stderr: $!"); + } else { + # If run under prove/TAP, we don't want to confuse the test runner. + open(STDOUT, '>&', *STDERR) or error("Redirect stdout to stderr: $!"); + } + exec(@cmd); + } + waitpid($pid, 0) == $pid or BAIL_OUT("waitpid($pid) failed: $!"); + return 1 if not $?; + return 0; +} + +sub _prepare_test_root { + my $dir = tempdir(CLEANUP => 1); + if (not mkdir("$dir/debian", 0777)) { + error("mkdir $dir/debian failed: $!") + if $! != EEXIST; + } else { + # auto seed it + my @files = qw( + debian/control + debian/compat + debian/changelog + ); + for my $file (@files) { + copy_file($file, "${dir}/${file}"); + } + if (@::TEST_DH_EXTRA_TEMPLATE_FILES) { + my $test_dir = ($TEST_DIR //= dirname($0)); + my $fixture_dir = $::TEST_DH_FIXTURE_DIR // '.'; + my $actual_dir = "$test_dir/$fixture_dir"; + for my $file (@::TEST_DH_EXTRA_TEMPLATE_FILES) { + if (index($file, '/') > -1) { + my $install_dir = dirname($file); + mkdirs($install_dir); + } + copy_file("${actual_dir}/${file}", "${dir}/${file}"); + } + } + } + return $dir; +} + +sub each_compat_from_x_to_and_incl_y_subtest($$&) { + my ($compat, $high_compat, $code) = @_; + my $lowest = Debian::Debhelper::Dh_Lib::MIN_COMPAT_LEVEL; + my $highest = Debian::Debhelper::Dh_Lib::MAX_COMPAT_LEVEL; + error("compat $compat is no longer support! Min compat $lowest") + if $compat < $lowest; + error("$high_compat is from the future! Max known is $highest") + if $high_compat > $highest; + subtest '' => sub { + # Keep $dir alive until the test is over + my $dir = _prepare_test_root; + chdir($dir) or error("chdir($dir): $!"); + while ($compat <= $high_compat) { + local $TEST_DH_COMPAT = $compat; + $code->($compat); + ++$compat; + } + chdir($START_DIR) or error("chdir($START_DIR): $!"); + }; + return; +} + +sub each_compat_up_to_and_incl_subtest($&) { + unshift(@_, Debian::Debhelper::Dh_Lib::MIN_COMPAT_LEVEL); + goto \&each_compat_from_x_to_and_incl_y_subtest; +} + +sub each_compat_from_and_above_subtest($&) { + splice(@_, 1, 0, Debian::Debhelper::Dh_Lib::MAX_COMPAT_LEVEL); + goto \&each_compat_from_x_to_and_incl_y_subtest; +} + +sub each_compat_subtest(&) { + unshift(@_, + Debian::Debhelper::Dh_Lib::MIN_COMPAT_LEVEL, + Debian::Debhelper::Dh_Lib::MAX_COMPAT_LEVEL); + goto \&each_compat_from_x_to_and_incl_y_subtest; +} + +sub create_empty_file { + my ($file, $chmod) = @_; + open(my $fd, '>', $file) or die("open($file): $!\n"); + close($fd) or die("close($file): $!\n"); + if (defined($chmod)) { + chmod($chmod, $file) + or die(sprintf('chmod(%04o, %s): %s', $chmod, $file, $!)); + } + return 1; +} + +sub readlines { + my ($h) = @_; + my @lines = <$h>; + close $h; + chop @lines; + return \@lines; +} + +# In *inst order (find_script will shuffle them around for *rm order) +my @SNIPPET_FILE_TEMPLATES = ( + 'debian/#PACKAGE#.#SCRIPT#.debhelper', + 'debian/.debhelper/generated/#PACKAGE#/#SCRIPT#.service', +); + +sub find_script { + my ($package, $script) = @_; + my @files; + for my $template (@SNIPPET_FILE_TEMPLATES) { + my $file = ($template =~ s/#PACKAGE#/$package/r); + $file =~ s/#SCRIPT#/$script/; + push(@files, $file) if -f $file; + } + if ($script eq 'postrm' or $script eq 'prerm') { + @files = reverse(@files); + } + return @files; +} + +sub non_deprecated_compat_levels() { + my $start = Debian::Debhelper::Dh_Lib::LOWEST_NON_DEPRECATED_COMPAT_LEVEL; + my $end = Debian::Debhelper::Dh_Lib::MAX_COMPAT_LEVEL; + return ($start..$end); +} + +1; diff --git a/t/buildsystems/01-build-system-basic-api.t b/t/buildsystems/01-build-system-basic-api.t new file mode 100755 index 0000000..dfb26d2 --- /dev/null +++ b/t/buildsystems/01-build-system-basic-api.t @@ -0,0 +1,43 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More tests => 12; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use Debian::Debhelper::Dh_Lib qw(!dirname); +use Debian::Debhelper::Buildsystem; + +my $BS_CLASS = 'Debian::Debhelper::Buildsystem'; + + +build_system_path_apis(); + +# Bulk tests +sub build_system_path_apis { + ### Test Buildsystem class API methods + is( $BS_CLASS->canonpath("path/to/the/./nowhere/../../somewhere"), + "path/to/somewhere", "canonpath no1" ); + is( $BS_CLASS->canonpath("path/to/../forward/../../somewhere"), + "somewhere","canonpath no2" ); + is( $BS_CLASS->canonpath("path/to/../../../somewhere"), + "../somewhere","canonpath no3" ); + is( $BS_CLASS->canonpath("./"), ".", "canonpath no4" ); + is( $BS_CLASS->canonpath("/absolute/path/./somewhere/../to/nowhere"), + "/absolute/path/to/nowhere", "canonpath no5" ); + is( $BS_CLASS->_rel2rel("path/my/file", "path/my", "/tmp"), + "file", "_rel2rel no1" ); + is( $BS_CLASS->_rel2rel("path/dir/file", "path/my", "/tmp"), + "../dir/file", "_rel2rel no2" ); + is( $BS_CLASS->_rel2rel("file", "/root/path/my", "/root"), + "/root/file", "_rel2rel abs no3" ); + is( $BS_CLASS->_rel2rel(".", ".", "/tmp"), ".", "_rel2rel no4" ); + is( $BS_CLASS->_rel2rel("path", "path/", "/tmp"), ".", "_rel2rel no5" ); + is( $BS_CLASS->_rel2rel("/absolute/path", "anybase", "/tmp"), + "/absolute/path", "_rel2rel abs no6"); + is( $BS_CLASS->_rel2rel("relative/path", "/absolute/base", "/tmp"), + "/tmp/relative/path", "_rel2rel abs no7"); +} + diff --git a/t/buildsystems/02-make-jobserver-makeflags.t b/t/buildsystems/02-make-jobserver-makeflags.t new file mode 100755 index 0000000..9469759 --- /dev/null +++ b/t/buildsystems/02-make-jobserver-makeflags.t @@ -0,0 +1,57 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More tests => 9; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use Debian::Debhelper::Dh_Lib qw(!dirname); + +# Test clean_jobserver_makeflags. + +test_clean_jobserver_makeflags('--jobserver-fds=103,104 -j', + undef, + 'unset makeflags'); + +test_clean_jobserver_makeflags('-a --jobserver-fds=103,104 -j -b', + '-a -b', + 'clean makeflags'); + +test_clean_jobserver_makeflags(' --jobserver-fds=1,2 -j ', + undef, + 'unset makeflags'); + +test_clean_jobserver_makeflags('-a -j -b', + '-a -j -b', + 'clean makeflags does not remove -j'); + +test_clean_jobserver_makeflags('-a --jobs -b', + '-a --jobs -b', + 'clean makeflags does not remove --jobs'); + +test_clean_jobserver_makeflags('-j6', + '-j6', + 'clean makeflags does not remove -j6'); + +test_clean_jobserver_makeflags('-a -j6 --jobs=7', + '-a -j6 --jobs=7', + 'clean makeflags does not remove -j or --jobs'); + +test_clean_jobserver_makeflags('-j6 --jobserver-fds=103,104 --jobs=8', + '-j6 --jobs=8', + 'jobserver options removed'); + +test_clean_jobserver_makeflags('-j6 --jobserver-auth=103,104 --jobs=8', + '-j6 --jobs=8', + 'jobserver options removed'); + +sub test_clean_jobserver_makeflags { + my ($orig, $expected, $test) = @_; + + local $ENV{MAKEFLAGS} = $orig; + clean_jobserver_makeflags(); + is($ENV{MAKEFLAGS}, $expected, $test); +} + diff --git a/t/buildsystems/03-bs-auto-buildable.t b/t/buildsystems/03-bs-auto-buildable.t new file mode 100755 index 0000000..df4405b --- /dev/null +++ b/t/buildsystems/03-bs-auto-buildable.t @@ -0,0 +1,218 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More tests => 187; + +use File::Temp qw(tempdir); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); +use Debian::Debhelper::Dh_Buildsystems; + +my @STEPS = qw(configure build test install clean); + +### Test check_auto_buildable() of each buildsystem +sub test_check_auto_buildable { + my ($bs, $config, $expected) = @_; + + if (! ref $expected) { + my %all_steps; + $all_steps{$_} = $expected foreach (@STEPS); + $expected = \%all_steps; + } + for my $step (@STEPS) { + my $e = 0; + if (exists $expected->{$step}) { + $e = $expected->{$step}; + } elsif (exists $expected->{default}) { + $e = $expected->{default}; + } + is( $bs->check_auto_buildable($step), $e, + $bs->NAME() . "($config): check_auto_buildable($step) == $e" ); + } +} + +sub test_autoselection { + my ($testname, $expected, %args) = @_; + for my $step (@STEPS) { + my $bs = load_buildsystem({'enable-thirdparty' => 0}, $step, @_); + my $e = $expected; + $e = $expected->{$step} if ref $expected; + if (defined $bs) { + is( $bs->NAME(), $e, "autoselection($testname): $step=".((defined $e)?$e:'undef') ); + } + else { + is ( undef, $e, "autoselection($testname): $step=".((defined $e)?$e:'undef') ); + } + &{$args{"code_$step"}}() if exists $args{"code_$step"}; + } +} + +my $TEMP_DIR = tempdir('tmp.XXXXXXX', CLEANUP => 1); +my $sourcedir = "${TEMP_DIR}/source"; +my $builddir = "${TEMP_DIR}/build"; +my %options = ( + 'builddir' => $builddir, + 'sourcedir' => $sourcedir, +); +make_path($sourcedir, $builddir); +use Config; +my $libpath = $ENV{AUTOPKGTEST_TMP} ? $Config{vendorlib} : "$Test::DH::ROOT_DIR/lib"; +my @bs = load_all_buildsystems([ $libpath ], %options); +my %bs; +my @names = map { $_->NAME() } @bs; + +ok(@Debian::Debhelper::Dh_Buildsystems::BUILDSYSTEMS >= 1, "some build systems are built in" ); +is_deeply( \@names, \@Debian::Debhelper::Dh_Buildsystems::BUILDSYSTEMS, "load_all_buildsystems() loads all built-in buildsystems" ); + +# check_auto_buildable() fails with numeric 0 +for my $bs (@bs) { + test_check_auto_buildable($bs, "fails with numeric 0", 0); + $bs{$bs->NAME()} = $bs; +} + +run_auto_buildable_tests(); + +remove_tree($sourcedir, $builddir); +make_path($sourcedir, $builddir); + +run_autoselection_tests(); + + +#### Bulk of test code #### + +sub run_auto_buildable_tests { + create_empty_file("${sourcedir}/configure", 0755); + test_check_auto_buildable($bs{autoconf}, "configure", { configure => 1, clean => 1 }); + rm_files("${sourcedir}/configure"); + + create_empty_file("${sourcedir}/CMakeLists.txt"); + test_check_auto_buildable($bs{'cmake+makefile'}, "CMakeLists.txt", { configure => 1, clean => 1 }); + rm_files("${sourcedir}/CMakeLists.txt"); + + create_empty_file("${sourcedir}/Makefile.PL"); + test_check_auto_buildable($bs{perl_makemaker}, "Makefile.PL", { configure => 1 }); + rm_files("${sourcedir}/Makefile.PL"); + + create_empty_file("${sourcedir}/meson.build"); + test_check_auto_buildable($bs{'meson+ninja'}, "meson.build", { configure => 1, clean => 1 }); + # Leave meson.build + + create_empty_file("${builddir}/build.ninja"); + test_check_auto_buildable($bs{ninja}, "build.ninja", { configure => 1, build => 1, clean => 1, install => 1, test => 1 }); + # Leave ninja.build + + # Meson + ninja + test_check_auto_buildable($bs{'meson+ninja'}, "meson.build+build.ninja", { configure => 1, build => 1, clean => 1, install => 1, test => 1 }); + rm_files("${sourcedir}/meson.build", "${builddir}/build.ninja"); + + # With Makefile + create_empty_file("$builddir/Makefile"); + test_check_auto_buildable($bs{makefile}, "Makefile", 1); + + # ... +autoconf + create_empty_file("${sourcedir}/configure", 0755); + test_check_auto_buildable($bs{autoconf}, "configure+Makefile", { configure => 1, test => 1, build => 1, install => 1, clean => 1 }); + rm_files("${sourcedir}/configure"); + + # ... +cmake + create_empty_file("${sourcedir}/CMakeLists.txt"); + test_check_auto_buildable($bs{'cmake+makefile'}, "CMakeLists.txt+Makefile", 1); + create_empty_file("$builddir/CMakeCache.txt"); # strong evidence that cmake was run + test_check_auto_buildable($bs{'cmake+makefile'}, "CMakeCache.txt+Makefile", 2); + rm_files("${builddir}/Makefile", "${sourcedir}/CMakeLists.txt"); + + # Makefile.PL forces in-source + #(see note in check_auto_buildable() why always 1 here) + create_empty_file("${sourcedir}/Makefile.PL"); + create_empty_file("${sourcedir}/Makefile"); + test_check_auto_buildable($bs{perl_makemaker}, "Makefile.PL+Makefile", 1); + rm_files("${sourcedir}/Makefile.PL", "${sourcedir}/Makefile"); + + # Perl Build.PL - handles always + test_check_auto_buildable($bs{perl_build}, "no Build.PL", 0); + create_empty_file("${sourcedir}/Build.PL"); + test_check_auto_buildable($bs{perl_build}, "Build.PL", { configure => 1 }); + create_empty_file("${sourcedir}/Build"); # forced in source + test_check_auto_buildable($bs{perl_build}, "Build.PL+Build", 1); + rm_files("${sourcedir}/Build.PL", "${sourcedir}/Build"); + + # Python Distutils + test_check_auto_buildable($bs{python_distutils}, "no setup.py", 0); + create_empty_file("${sourcedir}/setup.py"); + test_check_auto_buildable($bs{python_distutils}, "setup.py", 1); + rm_files("${sourcedir}/setup.py"); +} + +sub run_autoselection_tests { + # Auto-select nothing when no supported build system can be found + # (see #557006). + test_autoselection("auto-selects nothing", undef, %options); + + # Autoconf + create_empty_file("${sourcedir}/configure", 0755); + create_empty_file("${builddir}/Makefile"); + test_autoselection("autoconf", + { configure => "autoconf", build => "autoconf", + test => "autoconf", install => "autoconf", + clean => "autoconf" + }, %options); + rm_files("${sourcedir}/configure", "${builddir}/Makefile"); + + + # Perl Makemaker (build, test, clean fail with builddir set [not supported]) + create_empty_file("${sourcedir}/Makefile.PL"); + create_empty_file("${sourcedir}/Makefile"); + test_autoselection("perl_makemaker", "perl_makemaker", %options); + rm_files("${sourcedir}/Makefile.PL", "${sourcedir}/Makefile"); + + + # Makefile + create_empty_file("$builddir/Makefile"); + test_autoselection("makefile", "makefile", %options); + rm_files("$builddir/Makefile"); + + # Python Distutils + create_empty_file("${sourcedir}/setup.py"); + test_autoselection("python_distutils", "python_distutils", %options); + rm_files("${sourcedir}/setup.py"); + + # Perl Build + create_empty_file("${sourcedir}/Build.PL"); + create_empty_file("${sourcedir}/Build"); + test_autoselection("perl_build", "perl_build", %options); + rm_files("${sourcedir}/Build.PL", "${sourcedir}/Build"); + + # CMake + create_empty_file("${sourcedir}/CMakeLists.txt"); + test_autoselection("cmake without CMakeCache.txt", + { configure => "cmake+makefile", build => "makefile", + test => "makefile", install => "makefile", + clean => "makefile" + }, + %options, + code_configure => sub { + create_empty_file("$builddir/Makefile"); + }); + rm_files("${sourcedir}/CMakeLists.txt", "$builddir/Makefile"); + + create_empty_file("${sourcedir}/CMakeLists.txt"); + test_autoselection("cmake with CMakeCache.txt", + "cmake+makefile", + %options, + code_configure => sub { + create_empty_file("$builddir/Makefile"); + create_empty_file("$builddir/CMakeCache.txt"); + }); + rm_files("${sourcedir}/CMakeLists.txt", "$builddir/Makefile", "$builddir/CMakeCache.txt"); + + create_empty_file("${sourcedir}/CMakeLists.txt"); + create_empty_file("$builddir/Makefile"); + test_autoselection("cmake and existing Makefile", "makefile", %options); + rm_files("${sourcedir}/CMakeLists.txt", "$builddir/Makefile"); + +}; + diff --git a/t/buildsystems/04-dh_auto_do_autoconf.t b/t/buildsystems/04-dh_auto_do_autoconf.t new file mode 100755 index 0000000..a1346e4 --- /dev/null +++ b/t/buildsystems/04-dh_auto_do_autoconf.t @@ -0,0 +1,88 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More tests => 31; + +use File::Temp qw(tempdir); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); +use Debian::Debhelper::Dh_Buildsystems; + +# Let the tests to be run from anywhere but currect directory +# is expected to be the one where this test lives in. +chdir File::Basename::dirname($0) or die "Unable to chdir to ".File::Basename::dirname($0); + +$Test::DH::TEST_DH_COMPAT = 10; + +# Build the autoconf test package +sub dh_auto_do_autoconf { + my ($sourcedir, $builddir, %args) = @_; + + my (@lines, @extra_args); + my $buildpath = $sourcedir; + my @dh_auto_args = ("-D", $sourcedir); + my $dh_auto_str = "-D $sourcedir"; + if ($builddir) { + push @dh_auto_args, "-B", $builddir; + $dh_auto_str .= " -B $builddir"; + $buildpath = $builddir; + } + + my $do_dh_auto = sub { + my ($step) = @_; + my @extra_args; + my $extra_str = ""; + if (exists $args{"${step}_args"}) { + push @extra_args, @{$args{"${step}_args"}}; + $extra_str .= " $_" foreach (@extra_args); + } + ok(run_dh_tool({ 'quiet' => 1 }, "dh_auto_${step}", @dh_auto_args, '--', @extra_args), + "dh_auto_$step $dh_auto_str$extra_str"); + return @extra_args; + }; + + @extra_args = &$do_dh_auto('configure'); + ok ( -f "$buildpath/Makefile", "$buildpath/Makefile exists" ); + @lines=(); + if ( ok(open(FILE, '<', "$buildpath/stamp_configure"), "$buildpath/stamp_configure exists") ) { + @lines = @{readlines(\*FILE)}; + close(FILE); + } + is_deeply( \@lines, \@extra_args, "$buildpath/stamp_configure contains extra args" ); + + &$do_dh_auto('build'); + ok ( -f "$buildpath/stamp_build", "$buildpath/stamp_build exists" ); + &$do_dh_auto('test'); + @lines=(); + if ( ok(open(FILE, '<', "$buildpath/stamp_test"), "$buildpath/stamp_test exists") ) { + @lines = @{readlines(\*FILE)}; + close(FILE); + } + is_deeply( \@lines, [ "VERBOSE=1" ], + "$buildpath/stamp_test contains VERBOSE=1" ); + &$do_dh_auto('install'); + @lines=(); + if ( ok(open(FILE, '<', "$buildpath/stamp_install"), "$buildpath/stamp_install exists") ) { + @lines = @{readlines(\*FILE)}; + close(FILE); + } + is_deeply( \@lines, [ "DESTDIR=".Cwd::getcwd()."/debian/testpackage" ], + "$buildpath/stamp_install contains DESTDIR" ); + &$do_dh_auto('clean'); + if ($builddir) { + ok ( ! -e "$buildpath", "builddir $buildpath was removed" ); + } + else { + ok ( ! -e "$buildpath/Makefile" && ! -e "$buildpath/stamp_configure", "Makefile and stamps gone" ); + } + ok ( -x "$sourcedir/configure", "configure script renamins after clean" ); +} + +dh_auto_do_autoconf('autoconf'); +dh_auto_do_autoconf('autoconf', 'bld/dir', configure_args => [ "--extra-autoconf-configure-arg" ]); +ok ( ! -e 'bld', "bld got deleted too" ); + diff --git a/t/buildsystems/05-load-build-system.t b/t/buildsystems/05-load-build-system.t new file mode 100755 index 0000000..23aed9f --- /dev/null +++ b/t/buildsystems/05-load-build-system.t @@ -0,0 +1,55 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Cwd; +use Test::More tests => 3; + +use File::Temp qw(tempdir); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); +use Debian::Debhelper::Buildsystem; + +my $DIR = dirname($0); +my $SCRIPT = './load-bs.pl'; # relative to $DIR +my $BS_CWD = Cwd::realpath($DIR) or error("cannot resolve ${DIR}: $!"); +my $BS_CLASS = 'Debian::Debhelper::Buildsystem'; +my $bs = $BS_CLASS->new(); +my $default_builddir = $bs->DEFAULT_BUILD_DIRECTORY(); +delete($ENV{'TEST_DH_SYSTEM'}); +delete($ENV{'TEST_DH_STEP'}); + +# NOTE: disabling parallel building explicitly (it might get automatically +# enabled if run under dpkg-buildpackage -jX) to make output deterministic. +is_deeply( try_load_bs(undef, 'configure', '--builddirectory=autoconf/bld dir', '--sourcedirectory', + 'autoconf', '--max-parallel=1'), + [ 'NAME=autoconf', 'builddir=autoconf/bld dir', "cwd=$BS_CWD", 'makecmd=make', 'parallel=1', 'sourcedir=autoconf' ], + "autoconf autoselection and sourcedir/builddir" ); + +is_deeply( try_load_bs('autoconf', 'build', '-Sautoconf', '-D', 'autoconf', '--max-parallel=1'), + [ 'NAME=autoconf', 'builddir=undef', "cwd=$BS_CWD", 'makecmd=make', 'parallel=1', 'sourcedir=autoconf' ], + "forced autoconf and sourcedir" ); + +is_deeply( try_load_bs('autoconf', 'build', '-B', '-Sautoconf', '--max-parallel=1'), + [ 'NAME=autoconf', "builddir=$default_builddir", "cwd=$BS_CWD", 'makecmd=make', 'parallel=1', 'sourcedir=.' ], + "forced autoconf and default build directory" ); + +sub try_load_bs { + my ($system, $step, @params) = @_; + my @lines; + my $pid = open(my $fd, '-|') // die("fork: $!"); + + if (not $pid) { + chdir($DIR) or die("chdir($DIR): $!"); + $ENV{'TEST_DH_SYSTEM'} = $system if defined($system); + $ENV{'TEST_DH_STEP'} = $step if defined($step); + exec($^X, $SCRIPT, @params); + } + @lines = map { chomp; $_ } <$fd>; + close($fd); # Ignore error + return \@lines; +} + diff --git a/t/buildsystems/06-buildsystem-mkdir-rmdir.t b/t/buildsystems/06-buildsystem-mkdir-rmdir.t new file mode 100755 index 0000000..c13b253 --- /dev/null +++ b/t/buildsystems/06-buildsystem-mkdir-rmdir.t @@ -0,0 +1,51 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Cwd; +use Test::More tests => 6; + +use File::Temp qw(tempdir); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use File::Path qw(make_path); +use Test::DH; +use Debian::Debhelper::Dh_Lib qw(!dirname); +use Debian::Debhelper::Buildsystem; + +chdir(dirname($0)) or die("chdir: $!"); +my $TEMP_DIR = tempdir('tmp.XXXXXXX', CLEANUP => 1); +my $sourcedir = $TEMP_DIR; +my $builddir = "${TEMP_DIR}/build"; +my $BS_CLASS = 'Debian::Debhelper::Buildsystem'; + +# Tests + +do_rmdir_builddir($sourcedir, $builddir); +ok ( ! -e $builddir, "testing rmdir_builddir() 1: builddir parent '$builddir' deleted" ); +ok ( -d $sourcedir, "testing rmdir_builddir() 1: sourcedir '$sourcedir' remains" ); + +$builddir = "$sourcedir/bld"; +do_rmdir_builddir($sourcedir, "$builddir/dir"); +ok ( ! -e $builddir, "testing rmdir_builddir() 2: builddir parent '$builddir' deleted" ); +ok ( -d $sourcedir, "testing rmdir_builddir() 2: sourcedir '$sourcedir' remains" ); + +$builddir = "$sourcedir/bld"; + +make_path($builddir, "$builddir/dir"); +create_empty_file("$builddir/afile"); +create_empty_file("$builddir/dir/afile2"); +do_rmdir_builddir($sourcedir, "$builddir/dir"); +ok ( ! -e "$builddir/dir", "testing rmdir_builddir() 3: builddir '$builddir/dir' not empty, but deleted" ); +ok ( -d $builddir, "testing rmdir_builddir() 3: builddir parent '$builddir' not empty, remains" ); + + +### Test Buildsystem::rmdir_builddir() +sub do_rmdir_builddir { + my ($sourcedir, $builddir) = @_; + my $system; + $system = $BS_CLASS->new(builddir => $builddir, sourcedir => $sourcedir); + $system->mkdir_builddir(); + $system->rmdir_builddir(); +} + diff --git a/t/buildsystems/autoconf/configure b/t/buildsystems/autoconf/configure new file mode 100755 index 0000000..5039783 --- /dev/null +++ b/t/buildsystems/autoconf/configure @@ -0,0 +1,84 @@ +#!/usr/bin/perl + +# Emulate autoconf behaviour and do some checks + +use strict; +use warnings; + +my @OPTIONS=qw( + ^--build=.*$ + ^--prefix=/usr$ + ^--includedir=\$\{prefix\}/include$ + ^--mandir=\$\{prefix\}/share/man$ + ^--infodir=\$\{prefix\}/share/info$ + ^--sysconfdir=/etc$ + ^--localstatedir=/var$ + ^--libdir=\$\{prefix\}/lib/.*$ + ^--disable-option-checking$ + ^--disable-silent-rules$ + ^--disable-maintainer-mode$ + ^--disable-dependency-tracking$ +); + +# Not always passed (e.g. --libexecdir is skipped in compat 12) +my @OPTIONAL_ARGUMENTS = qw( + ^--libexecdir=\$\{prefix\}/lib/.*$ +); + +# Verify if all command line arguments were passed +my @options = map { { regex => qr/$_/, + str => $_, + found => 0 } } @OPTIONS; +push(@options, map { { regex => qr/$_/, + str => $_, + found => 1 } } @OPTIONAL_ARGUMENTS); +my @extra_args; +ARGV_LOOP: foreach my $arg (@ARGV) { + foreach my $opt (@options) { + if ($arg =~ $opt->{regex}) { + $opt->{found} = 1; + next ARGV_LOOP; + } + } + # Extra / unrecognized argument + push @extra_args, $arg; +} + +my @notfound = grep { ! $_->{found} and $_ } @options; +if (@notfound) { + print STDERR "Error: the following default options were NOT passed\n"; + print STDERR " ", $_->{str}, "\n" foreach (@notfound); + exit 1; +} + +# Create a simple Makefile +open(MAKEFILE, ">", "Makefile"); +print MAKEFILE <<EOF; +CONFIGURE := $0 +all: stamp_configure \$(CONFIGURE) + \@echo Package built > stamp_build + +# Tests if dh_auto_test executes 'check' target if 'test' does not exist +check: \$(CONFIGURE) stamp_build + \@echo VERBOSE=\$(VERBOSE) > stamp_test + +install: stamp_build + \@echo DESTDIR=\$(DESTDIR) > stamp_install + +# Tests whether dh_auto_clean executes distclean but does not touch +# this target +clean: + echo "This should not have been executed" >&2 && exit 1 + +distclean: + \@rm -f stamp_* Makefile + +.PHONY: all check install clean distclean +EOF +close MAKEFILE; + +open(STAMP, ">", "stamp_configure"); +print STAMP $_, "\n" foreach (@extra_args); +close STAMP; + +exit 0; diff --git a/t/buildsystems/buildsystem_tests.t b/t/buildsystems/buildsystem_tests.t new file mode 100755 index 0000000..eaa2380 --- /dev/null +++ b/t/buildsystems/buildsystem_tests.t @@ -0,0 +1,293 @@ +#!/usr/bin/perl + +use Test::More tests => 85; + +use strict; +use warnings; +use IPC::Open2; +use Cwd (); +use File::Temp qw(tempfile); +use File::Basename (); + +# Let the tests to be run from anywhere but currect directory +# is expected to be the one where this test lives in. +chdir File::Basename::dirname($0) or die "Unable to chdir to ".File::Basename::dirname($0); + +use_ok( 'Debian::Debhelper::Dh_Lib' ); +use_ok( 'Debian::Debhelper::Buildsystem' ); +use_ok( 'Debian::Debhelper::Dh_Buildsystems' ); + +my $TOPDIR = $ENV{AUTOPKGTEST_TMP} ? '/usr/bin' : '../..'; +my @STEPS = qw(configure build test install clean); +my $BS_CLASS = 'Debian::Debhelper::Buildsystem'; + +my ($bs); +my ($tmp, @tmp, %tmp); +my ($default_builddir); + +### Common subs #### +sub readlines { + my $h=shift; + my @lines = <$h>; + close $h; + chop @lines; + return \@lines; +} + +sub process_stdout { + my ($cmdline, $stdin) = @_; + my ($reader, $writer); + + my $pid = open2($reader, $writer, $cmdline) or die "Unable to exec $cmdline"; + print $writer $stdin if $stdin; + close $writer; + waitpid($pid, 0); + $? = $? >> 8; # exit status + return readlines($reader); +} + +sub write_debian_rules { + my $contents=shift; + my $backup; + + if (-f "debian/rules") { + (undef, $backup) = tempfile(DIR => ".", OPEN => 0); + rename "debian/rules", $backup; + } + # Write debian/rules if requested + if ($contents) { + open(my $f, ">", "debian/rules"); + print $f $contents;; + close($f); + chmod 0755, "debian/rules"; + } + return $backup; +} + +### Test Buildsystem class path API methods under different configurations +sub test_buildsystem_paths_api { + my ($bs, $config, $expected)=@_; + + my $api_is = sub { + my ($got, $name)=@_; + is( $got, $expected->{$name}, "paths API ($config): $name") + }; + + &$api_is( $bs->get_sourcedir(), 'get_sourcedir()' ); + &$api_is( $bs->get_sourcepath("a/b"), 'get_sourcepath(a/b)' ); + &$api_is( $bs->get_builddir(), 'get_builddir()' ); + &$api_is( $bs->get_buildpath(), 'get_buildpath()' ); + &$api_is( $bs->get_buildpath("a/b"), 'get_buildpath(a/b)' ); + &$api_is( $bs->get_source_rel2builddir(), 'get_source_rel2builddir()' ); + &$api_is( $bs->get_source_rel2builddir("a/b"), 'get_source_rel2builddir(a/b)' ); + &$api_is( $bs->get_build_rel2sourcedir(), 'get_build_rel2sourcedir()' ); + &$api_is( $bs->get_build_rel2sourcedir("a/b"), 'get_build_rel2sourcedir(a/b)' ); +} + +# Defaults +$bs = $BS_CLASS->new(); +$default_builddir = $bs->DEFAULT_BUILD_DIRECTORY(); +%tmp = ( + "get_sourcedir()" => ".", + "get_sourcepath(a/b)" => "./a/b", + "get_builddir()" => undef, + "get_buildpath()" => ".", + "get_buildpath(a/b)" => "./a/b", + "get_source_rel2builddir()" => ".", + "get_source_rel2builddir(a/b)" => "./a/b", + "get_build_rel2sourcedir()" => ".", + "get_build_rel2sourcedir(a/b)" => "./a/b", +); +test_buildsystem_paths_api($bs, "no builddir, no sourcedir", \%tmp); + +# builddir=bld/dir +$bs = $BS_CLASS->new(builddir => "bld/dir"); +%tmp = ( + "get_sourcedir()" => ".", + "get_sourcepath(a/b)" => "./a/b", + "get_builddir()" => "bld/dir", + "get_buildpath()" => "bld/dir", + "get_buildpath(a/b)" => "bld/dir/a/b", + "get_source_rel2builddir()" => "../..", + "get_source_rel2builddir(a/b)" => "../../a/b", + "get_build_rel2sourcedir()" => "bld/dir", + "get_build_rel2sourcedir(a/b)" => "bld/dir/a/b", +); +test_buildsystem_paths_api($bs, "builddir=bld/dir, no sourcedir", \%tmp); + +# Default builddir, sourcedir=autoconf +$bs = $BS_CLASS->new(builddir => undef, sourcedir => "autoconf"); +%tmp = ( + "get_sourcedir()" => "autoconf", + "get_sourcepath(a/b)" => "autoconf/a/b", + "get_builddir()" => "$default_builddir", + "get_buildpath()" => "$default_builddir", + "get_buildpath(a/b)" => "$default_builddir/a/b", + "get_source_rel2builddir()" => "../autoconf", + "get_source_rel2builddir(a/b)" => "../autoconf/a/b", + "get_build_rel2sourcedir()" => "../$default_builddir", + "get_build_rel2sourcedir(a/b)" => "../$default_builddir/a/b", +); +test_buildsystem_paths_api($bs, "default builddir, sourcedir=autoconf", \%tmp); + +# sourcedir=autoconf (builddir should be dropped) +$bs = $BS_CLASS->new(builddir => "autoconf", sourcedir => "autoconf"); +%tmp = ( + "get_sourcedir()" => "autoconf", + "get_sourcepath(a/b)" => "autoconf/a/b", + "get_builddir()" => undef, + "get_buildpath()" => "autoconf", + "get_buildpath(a/b)" => "autoconf/a/b", + "get_source_rel2builddir()" => ".", + "get_source_rel2builddir(a/b)" => "./a/b", + "get_build_rel2sourcedir()" => ".", + "get_build_rel2sourcedir(a/b)" => "./a/b", +); +test_buildsystem_paths_api($bs, "no builddir, sourcedir=autoconf", \%tmp); + +# Prefer out of source tree building when +# sourcedir=builddir=autoconf hence builddir should be dropped. +$bs->prefer_out_of_source_building(builddir => "autoconf"); +test_buildsystem_paths_api($bs, "out of source preferred, sourcedir=builddir", \%tmp); + +# builddir=bld/dir, sourcedir=autoconf. Should be the same as sourcedir=autoconf. +$bs = $BS_CLASS->new(builddir => "bld/dir", sourcedir => "autoconf"); +$bs->enforce_in_source_building(); +test_buildsystem_paths_api($bs, "in source enforced, sourcedir=autoconf", \%tmp); + +# builddir=../bld/dir (relative to the curdir) +$bs = $BS_CLASS->new(builddir => "bld/dir/", sourcedir => "autoconf"); +%tmp = ( + "get_sourcedir()" => "autoconf", + "get_sourcepath(a/b)" => "autoconf/a/b", + "get_builddir()" => "bld/dir", + "get_buildpath()" => "bld/dir", + "get_buildpath(a/b)" => "bld/dir/a/b", + "get_source_rel2builddir()" => "../../autoconf", + "get_source_rel2builddir(a/b)" => "../../autoconf/a/b", + "get_build_rel2sourcedir()" => "../bld/dir", + "get_build_rel2sourcedir(a/b)" => "../bld/dir/a/b", +); +test_buildsystem_paths_api($bs, "builddir=../bld/dir, sourcedir=autoconf", \%tmp); + +#### Test parallel building and related options / routines +@tmp = ( $ENV{MAKEFLAGS}, $ENV{DEB_BUILD_OPTIONS} ); + + +# Test parallel building with makefile build system. +$ENV{MAKEFLAGS} = ""; +$ENV{DEB_BUILD_OPTIONS} = ""; + +sub do_parallel_mk { + my $dh_opts=shift || ""; + my $make_opts=shift || ""; + return process_stdout( + "LANG=C LC_ALL=C LC_MESSAGES=C $TOPDIR/dh_auto_build -Smakefile $dh_opts " . + "-- -s -f parallel.mk $make_opts 2>&1 >/dev/null", ""); +} + +sub test_isnt_parallel { + my ($got, $desc) = @_; + my @makemsgs = grep /^make[\d\[\]]*:/, @$got; + if (@makemsgs) { + like( $makemsgs[0], qr/Error 10/, $desc ); + } + else { + ok( scalar(@makemsgs) > 0, $desc ); + } +} + +sub test_is_parallel { + my ($got, $desc) = @_; + is_deeply( $got, [] , $desc ); + is( $?, 0, "(exit status=0) $desc"); +} + + +test_isnt_parallel( do_parallel_mk(), + "No parallel by default" ); +test_isnt_parallel( do_parallel_mk("parallel"), + "No parallel by default with --parallel" ); +test_isnt_parallel( do_parallel_mk("--max-parallel=5"), + "No parallel by default with --max-parallel=5" ); + +$ENV{DEB_BUILD_OPTIONS}="parallel=5"; +{ + local $ENV{DH_COMPAT} = 9; + # compat 9 is not parallel by default + test_isnt_parallel( do_parallel_mk(), + "DEB_BUILD_OPTIONS=parallel=5 without parallel options [c9]" ); +} + +# compat 10+ are parallel by default +test_is_parallel( do_parallel_mk(), + "DEB_BUILD_OPTIONS=parallel=5 without parallel options [current compat]" ); +test_is_parallel( do_parallel_mk("--parallel"), + "DEB_BUILD_OPTIONS=parallel=5 with --parallel" ); +test_is_parallel( do_parallel_mk("--max-parallel=2"), + "DEB_BUILD_OPTIONS=parallel=5 with --max-parallel=2" ); +test_isnt_parallel( do_parallel_mk("--max-parallel=1"), + "DEB_BUILD_OPTIONS=parallel=5 with --max-parallel=1" ); +test_isnt_parallel( do_parallel_mk("--no-parallel"), + "DEB_BUILD_OPTIONS=parallel=5 with --no-parallel" ); + +$ENV{MAKEFLAGS} = "--jobserver-fds=105,106 -j"; +$ENV{DEB_BUILD_OPTIONS}=""; +test_isnt_parallel( do_parallel_mk(), + "makefile.pm (no parallel): no make warnings about unavailable jobserver" ); +$ENV{DEB_BUILD_OPTIONS}="parallel=5"; +test_is_parallel( do_parallel_mk("--parallel"), + "DEB_BUILD_OPTIONS=parallel=5: no make warnings about unavail parent jobserver" ); + +$ENV{MAKEFLAGS} = "-j2"; +$ENV{DEB_BUILD_OPTIONS}=""; +test_isnt_parallel( do_parallel_mk(), + "MAKEFLAGS=-j2: dh_auto_build ignores MAKEFLAGS" ); +test_isnt_parallel( do_parallel_mk("--max-parallel=1"), + "MAKEFLAGS=-j2 with --max-parallel=1: dh_auto_build enforces -j1" ); + +# Test dh dpkg-buildpackage -jX detection +sub do_rules_for_parallel { + my $cmdline=shift || ""; + my $stdin=shift || ""; + return process_stdout("LANG=C LC_ALL=C LC_MESSAGES=C PATH=$TOPDIR:\$PATH " . + "make -f - $cmdline 2>&1 >/dev/null", $stdin); +} + +doit("ln", "-sf", "parallel.mk", "Makefile"); + +# Test if dh+override+$(MAKE) legacy punctuation hack work as before +$ENV{MAKEFLAGS} = "-j5"; +$ENV{DEB_BUILD_OPTIONS} = "parallel=5"; + +$tmp = write_debian_rules(<<'EOF'); +#!/usr/bin/make -f +export DEB_RULES_REQUIRES_ROOT:=no +override_dh_auto_build: + $(MAKE) +%: + @dh_clean > /dev/null 2>&1 + @+dh $@ --buildsystem=makefile --without autoreconf 2>/dev/null + @dh_clean > /dev/null 2>&1 +EOF +test_is_parallel( do_rules_for_parallel("build", "include debian/rules"), + "legacy punctuation hacks: +dh, override with \$(MAKE)" ); +unlink "debian/rules"; + +if (defined $tmp) { + rename($tmp, "debian/rules"); +} +else { + unlink("debian/rules"); +} + +# Clean up after parallel testing +END { + system("rm", "-f", "Makefile"); +} +$ENV{MAKEFLAGS} = $tmp[0] if defined $tmp[0]; +$ENV{DEB_BUILD_OPTIONS} = $tmp[1] if defined $tmp[1]; + +END { + system("$TOPDIR/dh_clean"); +} diff --git a/t/buildsystems/debian/changelog b/t/buildsystems/debian/changelog new file mode 100644 index 0000000..f902d89 --- /dev/null +++ b/t/buildsystems/debian/changelog @@ -0,0 +1,5 @@ +testpackage (1.0-1) unstable; urgency=low + + * Initial release. (Closes: #XXXXXX) + + -- Test <testing@nowhere> Tue, 09 Jun 2009 15:35:32 +0300 diff --git a/t/buildsystems/debian/control b/t/buildsystems/debian/control new file mode 100644 index 0000000..9c3134b --- /dev/null +++ b/t/buildsystems/debian/control @@ -0,0 +1,12 @@ +Source: testsrcpackage +Section: devel +Priority: optional +Maintainer: Test <testing@nowhere> +Standards-Version: 3.8.1 +Build-Depends: debhelper-compat (= 12) +Rules-Requires-Root: no + +Package: testpackage +Architecture: all +Description: short description + Long description diff --git a/t/buildsystems/load-bs.pl b/t/buildsystems/load-bs.pl new file mode 100755 index 0000000..aeb5ea8 --- /dev/null +++ b/t/buildsystems/load-bs.pl @@ -0,0 +1,16 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Debian::Debhelper::Dh_Buildsystems; + +buildsystems_init(); +my $system = $ENV{'TEST_DH_SYSTEM'}; +my $step = $ENV{'TEST_DH_STEP'}; +my $bs = load_buildsystem($system, $step); +if (defined $bs) { + print 'NAME=', $bs->NAME(), "\n"; + print $_, "=", (defined $bs->{$_}) ? $bs->{$_} : 'undef', "\n" + foreach (sort keys %$bs); +} + diff --git a/t/buildsystems/parallel.mk b/t/buildsystems/parallel.mk new file mode 100644 index 0000000..3e0d201 --- /dev/null +++ b/t/buildsystems/parallel.mk @@ -0,0 +1,21 @@ +all: FIRST SECOND + +TMPFILE ?= $(CURDIR)/parallel.mk.lock + +rmtmpfile: + @rm -f "$(TMPFILE)" + +FIRST: rmtmpfile + @c=0; \ + while [ $$c -le 5 ] && \ + ([ ! -e "$(TMPFILE)" ] || [ "`cat "$(TMPFILE)"`" != "SECOND" ]); do \ + c=$$(($$c+1)); \ + sleep 0.1; \ + done; \ + rm -f "$(TMPFILE)"; \ + if [ $$c -gt 5 ]; then exit 10; else exit 0; fi + +SECOND: rmtmpfile + @echo $@ > "$(TMPFILE)" + +.PHONY: all FIRST SECOND rmtmpfile diff --git a/t/debhelper-compat/debian/control b/t/debhelper-compat/debian/control new file mode 100644 index 0000000..1f18f4d --- /dev/null +++ b/t/debhelper-compat/debian/control @@ -0,0 +1,12 @@ +Source: foo +Section: misc +Priority: optional +Build-Depends: BUILD_DEPENDS +Maintainer: Test <testing@nowhere> +Rules-Requires-Root: no +Standards-Version: 3.9.8 + +Package: foo +Architecture: all +Description: package foo + Package foo diff --git a/t/debhelper-compat/syntax.t b/t/debhelper-compat/syntax.t new file mode 100755 index 0000000..7fe0307 --- /dev/null +++ b/t/debhelper-compat/syntax.t @@ -0,0 +1,82 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; + +use File::Basename qw(dirname); +use File::Temp qw(tempdir); +use lib dirname(dirname(__FILE__)); +use Test::DH; + +use Debian::Debhelper::Dh_Lib qw(!dirname); + +my $TEST_DIR = dirname(__FILE__); + +sub test_build_depends { + my ($level, $build_depends) = @_; + my $dir = tempdir(CLEANUP => 1); + if (not mkdir("$dir/debian", 0777)) { + error("mkdir $dir/debian failed: $!"); + } + open my $in, '<', "$TEST_DIR/debian/control" or + error("open $TEST_DIR/debian/control failed: $!"); + open my $out, '>', "$dir/debian/control" or + error("open $dir/debian/control failed: $!"); + while (<$in>) { + s/BUILD_DEPENDS/$build_depends/; + print $out $_ or + error("write to $dir/debian/control failed: $!"); + } + close($out) or + error("close $dir/debian/control failed: $!"); + close($in); + + my $start_dir = Test::DH::getcwd(); + chdir($dir) or error("chdir($dir): $!"); + + plan(tests => 5); + + local $ENV{DH_INTERNAL_TESTSUITE_SILENT_WARNINGS} = 1; + Debian::Debhelper::Dh_Lib::resetpackages; + Debian::Debhelper::Dh_Lib::resetcompat; + my @pkgs = getpackages; + ok(scalar @pkgs == 1); + ok($pkgs[0] eq 'foo'); + + ok(compat($level)); + ok(compat($level + 1)); + ok(!compat($level - 1)); + + chdir($start_dir) or + error("chdir($start_dir): $!"); +} + +my @levels = non_deprecated_compat_levels; +plan(tests => scalar @levels); + +for my $level (@levels) { + subtest "compat $level" => sub { + plan(tests => 7); + subtest 'only' => sub { + test_build_depends($level, "debhelper-compat (= $level)"); + }; + subtest 'first' => sub { + test_build_depends($level, "debhelper-compat (= $level), bar"); + }; + subtest 'second' => sub { + test_build_depends($level, "bar, debhelper-compat (= $level)"); + }; + subtest 'first-nl' => sub { + test_build_depends($level, "debhelper-compat (= $level),\n bar"); + }; + subtest 'second-nl' => sub { + test_build_depends($level, "bar,\n debhelper-compat (= $level)"); + }; + subtest 'nl-first' => sub { + test_build_depends($level, "\n debhelper-compat (= $level),\n bar"); + }; + subtest 'nl-second' => sub { + test_build_depends($level, "\n bar,\n debhelper-compat (= $level)"); + }; + }; +} diff --git a/t/dh-lib.t b/t/dh-lib.t new file mode 100755 index 0000000..6e6f3cb --- /dev/null +++ b/t/dh-lib.t @@ -0,0 +1,63 @@ +#!/usr/bin/perl +package Debian::Debhelper::Dh_Lib::Test; +use strict; +use warnings; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(__FILE__); +use Test::DH; + +use Debian::Debhelper::Dh_Lib qw(!dirname); + +plan(tests => 2); + + +sub ok_autoscript_result { + ok(-f 'debian/testpackage.postinst.debhelper'); + open(my $fd, '<', 'debian/testpackage.postinst.debhelper') or die("open test-poinst: $!"); + my (@c) = <$fd>; + close($fd); + like(join('',@c), qr{update-rc\.d test-script test parms with"quote >/dev/null}); +} + + +each_compat_subtest { + + ok(autoscript('testpackage', 'postinst', 'postinst-init', + 's/#SCRIPT#/test-script/g; s/#INITPARMS#/test parms with\\"quote/g')); + ok_autoscript_result; + + ok(rm_files('debian/testpackage.postinst.debhelper')); + + ok(autoscript('testpackage', 'postinst', 'postinst-init', + sub { s/\#SCRIPT\#/test-script/g; s/\#INITPARMS\#/test parms with"quote/g } )); + ok_autoscript_result; + + ok(rm_files('debian/testpackage.postinst.debhelper')); + + ok(autoscript('testpackage', 'postinst', 'postinst-init', + { 'SCRIPT' => 'test-script', 'INITPARMS' => 'test parms with"quote' } )); + ok_autoscript_result; + + ok(rm_files('debian/testpackage.postinst.debhelper')); +}; + +$ENV{'FOO'} = "test"; +my @SUBST_TEST_OK = ( + ['unchanged', 'unchanged'], + ["unchanged\${\n}", "unchanged\${\n}"], # Newline is not an allowed part of ${} + ['raw dollar-sign ${}', 'raw dollar-sign $'], + ['${Dollar}${Space}${Dollar}', '$ $'], + ['Hello ${env:FOO}', 'Hello test'], + ['${Dollar}{Space}${}{Space}', '${Space}${Space}'], # We promise that ${Dollar}/${} never cause recursion + ['/usr/lib/${DEB_HOST_MULTIARCH}', '/usr/lib/' . dpkg_architecture_value('DEB_HOST_MULTIARCH')], +); + +each_compat_subtest { + for my $test (@SUBST_TEST_OK) { + my ($input, $expected_output) = @{$test}; + my $actual_output = Debian::Debhelper::Dh_Lib::_variable_substitution($input, 'test'); + is($actual_output, $expected_output, qq{${input}" => "${actual_output}" (should be: "${expected_output})"}); + } +}; diff --git a/t/dh-sequencer.t b/t/dh-sequencer.t new file mode 100755 index 0000000..f864386 --- /dev/null +++ b/t/dh-sequencer.t @@ -0,0 +1,282 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More; + +use Debian::Debhelper::Sequence; +use Debian::Debhelper::SequencerUtil; + +# Shorten variants of the sequences. +my @bd = (qw{ + dh_testdir + dh_auto_configure + dh_auto_build + dh_auto_test +}); +my @i = (qw{ + dh_testroot + dh_prep + dh_auto_install + + dh_install + dh_missing +}); +my @ba = ( + { + 'command' => 'dh_strip', + 'command-options' => [], + 'sequence-limitation' => SEQUENCE_TYPE_ARCH_ONLY, + }, + { + 'command' => 'dh_makeshlibs', + 'command-options' => [], + 'sequence-limitation' => SEQUENCE_TYPE_ARCH_ONLY, + }, + { + 'command' => 'dh_shlibdeps', + 'command-options' => [], + 'sequence-limitation' => SEQUENCE_TYPE_ARCH_ONLY, + } +); +my @b=qw{ + dh_installdeb + dh_gencontrol + dh_builddeb +}; +my @c=qw{ + dh_testdir + dh_auto_clean + dh_clean +}; + +my %sequences; + +sub _add_sequence { + my @args = @_; + my $seq = Debian::Debhelper::Sequence->new(@args); + my $name = $seq->name; + $sequences{$name} = $seq; + if ($seq->allowed_subsequences eq SEQUENCE_ARCH_INDEP_SUBSEQUENCES) { + for my $subseq ((SEQUENCE_TYPE_ARCH_ONLY, SEQUENCE_TYPE_INDEP_ONLY)) { + my $subname = "${name}-${subseq}"; + $sequences{$subname} = $seq; + } + } + return; +} + +_add_sequence('build', SEQUENCE_ARCH_INDEP_SUBSEQUENCES, @bd); +_add_sequence('install', SEQUENCE_ARCH_INDEP_SUBSEQUENCES, to_rules_target("build"), @i); +_add_sequence('binary', SEQUENCE_ARCH_INDEP_SUBSEQUENCES, to_rules_target("install"), @ba, @b); +_add_sequence('clean', SEQUENCE_NO_SUBSEQUENCES, @c); + +sub _cmd_names { + my (@input) = @_; + my @cmds; + for my $cmd (@input) { + if (ref($cmd) eq 'HASH') { + push(@cmds, $cmd->{'command'}); + } else { + push(@cmds, $cmd); + } + } + return \@cmds; +} + +my %sequences_unpacked = ( + 'build-indep' => _cmd_names(@bd), + 'build-arch' => _cmd_names(@bd), + 'build' => _cmd_names(@bd), + + 'install-indep' => _cmd_names(@bd, @i), + 'install-arch' => _cmd_names(@bd, @i), + 'install' => _cmd_names(@bd, @i), + + 'binary-indep' => _cmd_names(@bd, @i, @b), + 'binary-arch' => _cmd_names(@bd, @i, @ba, @b), + 'binary' => _cmd_names(@bd, @i, @ba, @b), + + 'clean' => _cmd_names(@c), +); + +plan tests => 21 + 3 * scalar(keys(%sequences)); + +# We will horse around with %EXPLICIT_TARGETS in this test; it should +# definitely not attempt to read d/rules or the test will be break. +$Debian::Debhelper::SequencerUtil::RULES_PARSED = 1; + + +is_deeply( + [unpack_sequence(\%sequences, 'build')], + [[], $sequences_unpacked{'build'}], + 'Inlined build sequence matches build-indep/build-arch'); + +is_deeply( + [unpack_sequence(\%sequences, 'install')], + [[], $sequences_unpacked{'install'}], + 'Inlined install sequence matches build-indep/build-arch + install commands'); + +is_deeply( + [unpack_sequence(\%sequences, 'binary-arch')], + [[], $sequences_unpacked{'binary-arch'}], + 'Inlined binary-arch sequence has all the commands'); + +is_deeply( + [unpack_sequence(\%sequences, 'binary-indep')], + [[], $sequences_unpacked{'binary-indep'}], + 'Inlined binary-indep sequence has all the commands except @bd'); + +is_deeply( + [unpack_sequence(\%sequences, 'binary')], + [[], $sequences_unpacked{'binary'}], + 'Inlined binary sequence has all the commands'); + + +is_deeply( + [unpack_sequence(\%sequences, 'binary', 0, { 'build' => 1, 'build-arch' => 1, 'build-indep' => 1})], + [[], _cmd_names(@i, @ba, @b)], + 'Inlined binary sequence with build-* done has @i, @ba and @b'); + + +is_deeply( + [unpack_sequence(\%sequences, 'binary', 0, { 'build-arch' => 1, 'build-indep' => 1})], + [[], _cmd_names(@i, @ba, @b)], + 'Inlined binary sequence with build-* done has @i, @ba and @b'); + +is_deeply( + [unpack_sequence(\%sequences, 'binary', 0, {}, 0)], + [[], _cmd_names(@bd, @i, @ba, @b)], + 'Inlined binary sequence and arch:all + arch:any is reduced to @bd, @i, @ba and @b'); + +is_deeply( + [unpack_sequence(\%sequences, 'binary', 0, {}, FLAG_OPT_SOURCE_BUILDS_NO_ARCH_PACKAGES)], + [[], _cmd_names(@bd, @i, @b)], + 'Inlined binary sequence and not arch:any is reduced to @bd, @i and @b'); + +is_deeply( + [unpack_sequence(\%sequences, 'binary', 0, {}, FLAG_OPT_SOURCE_BUILDS_NO_INDEP_PACKAGES)], + [[], _cmd_names(@bd, @i, @ba, @b)], + 'Inlined binary sequence and not arch:all is reduced to @bd, @i, @ba and @b'); + + +{ + local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'build-arch'} = 1; + local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'build-indep'} = 1; + + is_deeply( + [unpack_sequence(\%sequences, 'binary', 0, { 'build-arch' => 1, 'build-indep' => 1})], + [[], _cmd_names(@i, @ba, @b)], + 'Inlined binary sequence with build-* done has @i, @ba and @b'); + my $actual = [unpack_sequence(\%sequences, 'binary')]; + # @i should be "-i"-only, @ba + @b should be both. + # Unfortunately, unpack_sequence cannot show that. + my $expected = [[to_rules_target('build-arch'), to_rules_target('build-indep')], _cmd_names(@i, @ba, @b)]; + # Permit some fuzz on the order between build-arch and build-arch + if ($actual->[0][0] eq to_rules_target('build-indep')) { + $expected->[0][0] = to_rules_target('build-indep'); + $expected->[0][1] = to_rules_target('build-arch'); + } + is_deeply( + $actual, + $expected, + 'Inlined binary sequence with explicit build-* has explicit d/rules build-{arch,indep} + @i, @ba, @b'); + + is_deeply( + [unpack_sequence(\%sequences, 'binary', 0, { 'build' => 1})], + [[], _cmd_names(@i, @ba, @b)], + 'Inlined binary sequence with explicit build-* but done build has only @i, @ba and @b'); +} + +{ + local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'build-indep'} = 1; + is_deeply( + [ unpack_sequence(\%sequences, 'binary', 0, { 'build-arch' => 1 }) ], + [ [to_rules_target('build-indep')], _cmd_names(@i, @ba, @b) ], + 'Inlined binary sequence with build-arch done and build-indep explicit has d/rules build-indep + @i, @ba and @b'); + + is_deeply( + [ unpack_sequence(\%sequences, 'binary-arch', 0, { 'build-arch' => 1 }) ], + [ [], _cmd_names(@i, @ba, @b) ], + 'Inlined binary-arch sequence with build-arch done and build-indep explicit has @i, @ba and @b'); + + + is_deeply( + [ unpack_sequence(\%sequences, 'binary-indep', 0, { 'build-arch' => 1 }) ], + [ [to_rules_target('build-indep')], _cmd_names(@i, @b) ], + 'Inlined binary-indep sequence with build-arch done and build-indep explicit has d/rules build-indep + @i and @b'); +} + +{ + local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'build'} = 1; + + is_deeply( + [unpack_sequence(\%sequences, 'binary')], + [[to_rules_target('build')], _cmd_names(@i, @ba, @b)], + 'Inlined binary sequence has all the commands but build target is opaque'); + + is_deeply( + [unpack_sequence(\%sequences, 'binary', 0, { 'build' => 1, 'build-arch' => 1, 'build-indep' => 1})], + [[], _cmd_names(@i, @ba, @b)], + 'Inlined binary sequence has all the commands with build-* done and not build-target'); + + is_deeply( + [unpack_sequence(\%sequences, 'build')], + [[], $sequences_unpacked{'build'}], + 'build sequence is inlineable'); + + + # Compat <= 8 ignores explicit targets! + for my $seq_name (sort(keys(%sequences))) { + is_deeply( + [unpack_sequence(\%sequences, $seq_name, 1)], + [[], $sequences_unpacked{$seq_name}], + "Compat <= 8 ignores explicit build target in sequence ${seq_name}"); + } +} + +{ + local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'install-arch'} = 1; + + is_deeply( + [unpack_sequence(\%sequences, 'binary')], + # @bd_minimal, @bd and @i should be "-i"-only, @ba + @b should be both. + # Unfortunately, unpack_sequence cannot show that. + [[to_rules_target('install-arch')], _cmd_names(@bd, @i, @ba, @b)], + 'Inlined binary sequence has all the commands'); + + # Compat <= 8 ignores explicit targets! + for my $seq_name (sort(keys(%sequences))) { + is_deeply( + [unpack_sequence(\%sequences, $seq_name, 1)], + [[], $sequences_unpacked{$seq_name}], + "Compat <= 8 ignores explicit install-arch target in sequence ${seq_name}"); + } +} + +{ + local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'install-arch'} = 1; + local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'build'} = 1; + + my $actual = [unpack_sequence(\%sequences, 'binary')]; + # @i should be "-i"-only, @ba + @b should be both. + # Unfortunately, unpack_sequence cannot show that. + my $expected = [[to_rules_target('build'), to_rules_target('install-arch')], _cmd_names(@i, @ba, @b)]; + # Permit some fuzz on the order between build and install-arch + if ($actual->[0][0] eq to_rules_target('install-arch')) { + $expected->[0][0] = to_rules_target('install-arch'); + $expected->[0][1] = to_rules_target('build'); + } + is_deeply( + $actual, + $expected, + 'Inlined binary sequence has all the commands'); + + # Compat <= 8 ignores explicit targets! + for my $seq_name (sort(keys(%sequences))) { + is_deeply( + [unpack_sequence(\%sequences, $seq_name, 1)], + [[], $sequences_unpacked{$seq_name}], + "Compat <= 8 ignores explicit build + install-arch targets in sequence ${seq_name}"); + } +} diff --git a/t/dh_compress.t b/t/dh_compress.t new file mode 100755 index 0000000..1eb6156 --- /dev/null +++ b/t/dh_compress.t @@ -0,0 +1,114 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use File::Basename qw(dirname); +use lib dirname(__FILE__); +use Test::DH; + +use File::Path qw(make_path remove_tree); +use Test::More; +use Debian::Debhelper::Dh_Lib qw(!dirname); + +my $PREFIX = 'debian/debhelper/usr/share/doc/debhelper'; + +plan tests => 2; + +each_compat_subtest { + # we are testing compressing doc txt files + # foo.txt is 2k and bar.txt is 5k + mk_test_dir(); + + # default operation, bar.txt becomes bar.txt.gz and foo.txt is + # unchanged + ok(run_dh_tool('dh_compress')); + + is_deeply( + [map { s{${PREFIX}/}{}; $_ } sort glob "$PREFIX/*"], + [qw|bar.txt.gz foo.txt|], + '5k txt doc compressed, 2k txt doc not compressed' + ); + + mk_test_dir(); + + # now if I want to pass both on the command line to dh_compress, + # it should compress both + ok(run_dh_tool('dh_compress', '--', + 'usr/share/doc/debhelper/foo.txt', + 'usr/share/doc/debhelper/bar.txt')); + + is_deeply( + [map { s{${PREFIX}/}{}; $_ } sort glob "$PREFIX/*"], + [qw|bar.txt.gz foo.txt.gz|], + 'both 5k and 2k txt docs compressed' + ); + + mk_test_dir(); + + # absolute paths should also work + ok(run_dh_tool('dh_compress', '--', + '/usr/share/doc/debhelper/foo.txt', + '/usr/share/doc/debhelper/bar.txt')); + + is_deeply( + [map { s{${PREFIX}/}{}; $_ } sort glob "$PREFIX/*"], + [qw|bar.txt.gz foo.txt.gz|], + 'both 5k and 2k txt docs compressed by absolute path args' + ); + + rm_test_dir(); + + mk_test_dir(); + + is(system('cp', '-la', "${PREFIX}/bar.txt", "${PREFIX}/hardlink.txt"), 0, + 'create hardlink'); + + ok(run_dh_tool('dh_compress')); + + is_deeply( + [map { s{${PREFIX}/}{}; $_ } sort glob "$PREFIX/*"], + [qw|bar.txt.gz foo.txt hardlink.txt.gz|], + 'the 5k and its hardlink txt docs compressed' + ); + + # Verify that the hardlink is preserved. + my ($dev1, $inode1) = stat("${PREFIX}/bar.txt.gz") // error("stat ${PREFIX}/bar.txt.gz: $!"); + my ($dev2, $inode2) = stat("${PREFIX}/hardlink.txt.gz") // error("stat ${PREFIX}/hardlink.txt.gz: $!"); + + is($dev1, $dev2, 'Still hardlinked'); + is($inode1, $inode2, 'Still hardlinked'); + + rm_test_dir(); +}; + +each_compat_from_and_above_subtest(12, sub { + make_path("${PREFIX}/examples"); + create_file_of_size("${PREFIX}/examples/foo.py", 5120); + ok(run_dh_tool('dh_compress')); + ok(-f "${PREFIX}/examples/foo.py", "${PREFIX}/examples/foo.py is not compressed"); + ok(! -f "${PREFIX}/examples/foo.py.gz", "${PREFIX}/examples/foo.py is not compressed"); +}); + +sub create_file_of_size { + my ($filename, $size) = @_; + open(my $fh, '>', $filename) or error("open($filename) failed: $!"); + print {$fh} 'X' x $size; + close($fh) or error("close($filename) failed: $!"); +} + +sub mk_test_dir { + rm_test_dir(); + + make_path($PREFIX); + + create_file_of_size("${PREFIX}/foo.txt", 2048); + create_file_of_size("${PREFIX}/bar.txt", 5120); +} + +sub rm_test_dir { + remove_tree('debian/debhelper'); + + rm_files('debian/debhelper.debhelper.log'); +} + diff --git a/t/dh_install/01-basics.t b/t/dh_install/01-basics.t new file mode 100755 index 0000000..b266196 --- /dev/null +++ b/t/dh_install/01-basics.t @@ -0,0 +1,33 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); + +plan(tests => 2); + + +each_compat_subtest { + my ($compat) = @_; + # regular specification of file not in debian/tmp + create_empty_file('dh_install'); + ok(run_dh_tool('dh_install', 'dh_install', 'usr/bin')); + ok(-e "debian/debhelper/usr/bin/dh_install"); + remove_tree('debian/debhelper', 'debian/tmp'); +}; + +each_compat_subtest { + my ($compat) = @_; + # specification of file in subdir, not in debian/tmp + make_path('bar/usr/bin'); + create_empty_file('bar/usr/bin/foo'); + ok(run_dh_tool('dh_install', 'bar/usr/bin/foo')); + ok(-e "debian/debhelper/bar/usr/bin/foo"); + remove_tree('debian/debhelper', 'debian/tmp'); +}; + diff --git a/t/dh_install/02-bugs-53XXXX.t b/t/dh_install/02-bugs-53XXXX.t new file mode 100755 index 0000000..1c42489 --- /dev/null +++ b/t/dh_install/02-bugs-53XXXX.t @@ -0,0 +1,65 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); + +plan(tests => 4); + +each_compat_from_and_above_subtest(7, sub { + my ($compat) = @_; + # #537140: debian/tmp is explcitly specified despite being searched by + # default in v7+ + + make_path('debian/tmp/usr/bin'); + create_empty_file('debian/tmp/usr/bin/foo'); + create_empty_file('debian/tmp/usr/bin/bar'); + ok(run_dh_tool('dh_install', 'debian/tmp/usr/bin/foo')); + ok(-e "debian/debhelper/usr/bin/foo", "#537140 [${compat}]"); + ok(! -e "debian/debhelper/usr/bin/bar", "#537140 [${compat}]"); + remove_tree('debian/debhelper', 'debian/tmp'); +}); + +each_compat_from_and_above_subtest(7, sub { + my ($compat) = @_; + # #534565: glob expands to dangling symlink -> should install the dangling link + make_path('debian/tmp/usr/bin'); + make_symlink_raw_target('broken', 'debian/tmp/usr/bin/foo'); + create_empty_file('debian/tmp/usr/bin/bar'); + ok(run_dh_tool('dh_install', 'usr/bin/*')); + ok(-l "debian/debhelper/usr/bin/foo", "#534565 [${compat}]"); + ok(!-e "debian/debhelper/usr/bin/foo", "#534565 [${compat}]"); + ok(-e "debian/debhelper/usr/bin/bar", "#534565 [${compat}]"); + ok(!-l "debian/debhelper/usr/bin/bar", "#534565 [${compat}]"); + remove_tree('debian/debhelper', 'debian/tmp'); +}); + +each_compat_subtest { + my ($compat) = @_; + # #537017: --sourcedir=debian/tmp/foo is used + make_path('debian/tmp/foo/usr/bin'); + create_empty_file('debian/tmp/foo/usr/bin/foo'); + create_empty_file('debian/tmp/foo/usr/bin/bar'); + ok(run_dh_tool('dh_install', '--sourcedir=debian/tmp/foo', 'usr/bin/bar')); + ok(-e "debian/debhelper/usr/bin/bar", "#537017 [${compat}]"); + ok(!-e "debian/debhelper/usr/bin/foo", "#537017 [${compat}]"); + remove_tree('debian/debhelper', 'debian/tmp'); +}; + +each_compat_from_and_above_subtest(7, sub { + my ($compat) = @_; + # #535367: installation of entire top-level directory from debian/tmp + make_path('debian/tmp/usr/bin'); + create_empty_file('debian/tmp/usr/bin/foo'); + create_empty_file('debian/tmp/usr/bin/bar'); + ok(run_dh_tool('dh_install', 'usr')); + ok(-e "debian/debhelper/usr/bin/foo", "#535367 [${compat}]"); + ok(-e "debian/debhelper/usr/bin/bar", "#535367 [${compat}]"); + remove_tree('debian/debhelper', 'debian/tmp'); +}); + diff --git a/t/dh_install/03-866570-dont-install-from-host.t b/t/dh_install/03-866570-dont-install-from-host.t new file mode 100755 index 0000000..92345d1 --- /dev/null +++ b/t/dh_install/03-866570-dont-install-from-host.t @@ -0,0 +1,24 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); + +plan(tests => 1); + +each_compat_subtest { + my ($compat) = @_; + # #866570 - leading slashes must *not* pull things from the root FS. + make_path('bin'); + create_empty_file('bin/grep-i-licious'); + ok(run_dh_tool('dh_install', '/bin/grep*')); + ok(-e "debian/debhelper/bin/grep-i-licious", "#866570 [${compat}]"); + ok(!-e "debian/debhelper/bin/grep", "#866570 [${compat}]"); + remove_tree('debian/debhelper', 'debian/tmp'); +}; + diff --git a/t/dh_install/04-sourcedir.t b/t/dh_install/04-sourcedir.t new file mode 100755 index 0000000..83bd006 --- /dev/null +++ b/t/dh_install/04-sourcedir.t @@ -0,0 +1,47 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); + +plan(tests => 3); + + +each_compat_subtest { + my ($compat) = @_; + # redundant --sourcedir=debian/tmp in v7+ + make_path('debian/tmp/usr/bin'); + create_empty_file('debian/tmp/usr/bin/foo'); + create_empty_file('debian/tmp/usr/bin/bar'); + ok(run_dh_tool('dh_install', '--sourcedir=debian/tmp', 'usr/bin/foo')); + ok(-e "debian/debhelper/usr/bin/foo"); + ok(! -e "debian/debhelper/usr/bin/bar"); + remove_tree('debian/debhelper', 'debian/tmp'); +}; + +each_compat_subtest { + my ($compat) = @_; + # #534565: fallback use of debian/tmp in v7+ + make_path('debian/tmp/usr/bin'); + create_empty_file('debian/tmp/usr/bin/foo'); + create_empty_file('debian/tmp/usr/bin/bar'); + ok(run_dh_tool('dh_install', 'usr')); + ok(-e "debian/debhelper/usr/bin/foo", "#534565 [${compat}]"); + ok(-e "debian/debhelper/usr/bin/bar", "#534565 [${compat}]"); + remove_tree('debian/debhelper', 'debian/tmp'); +}; + +each_compat_subtest { + my ($compat) = @_; + # specification of file in source directory not in debian/tmp + make_path('bar/usr/bin'); + create_empty_file('bar/usr/bin/foo'); + ok(run_dh_tool('dh_install', '--sourcedir=bar', 'usr/bin/foo')); + ok(-e "debian/debhelper/usr/bin/foo"); + remove_tree('debian/debhelper', 'debian/tmp'); +}; diff --git a/t/dh_installchangelogs/debian/control b/t/dh_installchangelogs/debian/control new file mode 100644 index 0000000..4f4238e --- /dev/null +++ b/t/dh_installchangelogs/debian/control @@ -0,0 +1,10 @@ +Source: foo +Section: misc +Priority: optional +Maintainer: Test <testing@nowhere> +Standards-Version: 3.9.8 + +Package: foo +Architecture: all +Description: package foo + Package foo diff --git a/t/dh_installchangelogs/dh_installchangelogs.t b/t/dh_installchangelogs/dh_installchangelogs.t new file mode 100755 index 0000000..989a552 --- /dev/null +++ b/t/dh_installchangelogs/dh_installchangelogs.t @@ -0,0 +1,252 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use POSIX qw(locale_h); +use Test::More; +use Time::Piece; +use Time::Seconds qw(ONE_MONTH ONE_YEAR); + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; + +use constant TEST_DIR => dirname($0); +our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + debian/changelog + debian/control +)); + +# Force Time::Piece to generate dch-compliant timestamps (i.e. in English). +setlocale(LC_ALL, "C.UTF-8"); + +use constant CUTOFF_DATE_STR => "2019-07-06"; # oldstable = Debian 10 Buster +use constant CUTOFF_DATE => Time::Piece->strptime(CUTOFF_DATE_STR, "%Y-%m-%d"); +use constant MIN_NUM_ENTRIES => 4; + +sub install_changelog { + my ($latest_offset_years, $num_years, $is_binnmu) = @_; + $is_binnmu //= 0; + + my $entry_date_first = CUTOFF_DATE->add_years($latest_offset_years); + my $entry_date_stop = $entry_date_first->add_years(-$num_years); + + my $changelog = "${\TEST_DIR}/debian/changelog"; + + open(my $fd, ">", $changelog) or error("open($changelog): $!"); + + if ($is_binnmu) { + my $nmu_date = $entry_date_first->add_months(-1); + my $nmu_entry = entry_text($nmu_date, 1); + print($fd $nmu_entry); + } + + # Add one entry every three months ~= four per year. + my $entry_date = $entry_date_first; + while ($entry_date > $entry_date_stop) { + my $entry = entry_text($entry_date, 0); + print($fd $entry); + + $entry_date = $entry_date->add_months(-3); + } + close($fd); +} + +sub entry_text { + my ($entry_date, $is_binnmu) = @_; + my $entry_date_str = $entry_date->strftime("%a, %d %b %Y %T %z"); + my $ver = $entry_date->year . "." . $entry_date->mon . "-1"; + my $binnmu_text = ""; + + if ($is_binnmu) { + $binnmu_text = " binary-only=yes"; + $ver .= "+b1"; + } + + my $entry = ""; + $entry .= "foo ($ver) unstable; urgency=low$binnmu_text\n\n"; + $entry .= " * New release.\n\n"; + $entry .= " -- Test <testing\@nowhere> $entry_date_str\n\n"; + + return $entry; +} + +sub changelog_lines_pkg { + return changelog_lines("debian/changelog"); +} +sub changelog_lines_installed { + return changelog_lines("debian/foo/usr/share/doc/foo/changelog.Debian"); +} +sub changelog_lines_binnmu { + return changelog_lines("debian/foo/usr/share/doc/foo/changelog.Debian.all"); +} +sub changelog_lines { + my ($changelog) = @_; + open(my $fd, $changelog) or error("open($changelog): $!"); + my @lines = @{readlines($fd)}; + @lines = grep(!/^$/, @lines); + return @lines; +} + +sub dates_in_lines { + my @lines = @_; + my @lines_dates = grep(/^ -- /, @lines); + @lines_dates = map { (my $l = $_) =~ s/^\s*--\s+.*?\s+<[^>]*>\s+[A-Za-z]+, +//; $l } @lines_dates; + @lines_dates = map { Time::Piece->strptime($_, "%d %b %Y %T %z") } @lines_dates; + return @lines_dates; +} + +plan(tests => 8); + +# Test changelog with only recent entries (< oldstable) +my $years_after_cutoff = 2; +my $years_of_changelog = 2; +install_changelog($years_after_cutoff, $years_of_changelog); +each_compat_subtest { + my @lines_orig = changelog_lines_pkg(); + ok(run_dh_tool("dh_installchangelogs")); + my @lines = changelog_lines_installed(); + my @comments = grep(/^#/, @lines); + + is(@lines, @lines_orig); + is(@comments, 0); +}; + +# Test changelog with both recent and old entries +$years_after_cutoff = 1; +$years_of_changelog = 4; +install_changelog($years_after_cutoff, $years_of_changelog); +each_compat_subtest { + my @lines_orig = changelog_lines_pkg(); + ok(run_dh_tool("dh_installchangelogs")); + my @lines = changelog_lines_installed(); + my @entries = dates_in_lines(@lines); + my @entries_old = grep { $_ < CUTOFF_DATE } @entries; + my @comments = grep(/^#/, @lines); + + cmp_ok(@lines, "<", @lines_orig); + cmp_ok(@entries, ">", 1); + is(@entries_old, 0); + cmp_ok(@comments, ">=", 1); +}; + +# Test changelog with only old entries +$years_after_cutoff = -1; +$years_of_changelog = 2; +install_changelog($years_after_cutoff, $years_of_changelog); +each_compat_subtest { + my @lines_orig = changelog_lines_pkg(); + ok(run_dh_tool("dh_installchangelogs")); + my @lines = changelog_lines_installed(); + my @entries = dates_in_lines(@lines); + my @entries_old = grep { $_ < CUTOFF_DATE } @entries; + my @comments = grep(/^#/, @lines); + + cmp_ok(@lines, "<", @lines_orig); + is(@entries, MIN_NUM_ENTRIES); + is(@entries_old, MIN_NUM_ENTRIES); + cmp_ok(@comments, ">=", 1); +}; + +# Test changelog with only recent entries (< oldstable) + binNUM +$years_after_cutoff = 2; +$years_of_changelog = 2; +install_changelog($years_after_cutoff, $years_of_changelog, 1); +each_compat_subtest { + my @lines_orig = changelog_lines_pkg(); + my @entries_orig = dates_in_lines(@lines_orig); + ok(run_dh_tool("dh_installchangelogs")); + my @lines = changelog_lines_installed(); + my @entries = dates_in_lines(@lines); + my @entries_nmu = dates_in_lines(changelog_lines_binnmu()); + my @comments = grep(/^#/, @lines); + + is(@entries, @entries_orig-1); + is($entries[0], $entries_orig[1]); + is(@comments, 0); + + is(@entries_nmu, 1); +}; + +# Test changelog with both recent and old entries + binNMU +$years_after_cutoff = 1; +$years_of_changelog = 4; +install_changelog($years_after_cutoff, $years_of_changelog, 1); +each_compat_subtest { + my @lines_orig = changelog_lines_pkg(); + my @entries_orig = dates_in_lines(@lines_orig); + ok(run_dh_tool("dh_installchangelogs")); + my @lines = changelog_lines_installed(); + my @entries = dates_in_lines(@lines); + my @entries_old = grep { $_ < CUTOFF_DATE } @entries; + my @entries_nmu = dates_in_lines(changelog_lines_binnmu()); + my @comments = grep(/^#/, @lines); + + cmp_ok(@entries, "<", @entries_orig-1); + is($entries[0], $entries_orig[1]); + is(@entries_old, 0); + cmp_ok(@comments, ">=", 1); + + is(@entries_nmu, 1); +}; + +# Test changelog with only old entries + binNMU +$years_after_cutoff = -1; +$years_of_changelog = 2; +install_changelog($years_after_cutoff, $years_of_changelog, 1); +each_compat_subtest { + my @lines_orig = changelog_lines_pkg(); + my @entries_orig = dates_in_lines(@lines_orig); + ok(run_dh_tool("dh_installchangelogs")); + my @lines = changelog_lines_installed(); + my @entries = dates_in_lines(@lines); + my @entries_old = grep { $_ < CUTOFF_DATE } @entries; + my @entries_nmu = dates_in_lines(changelog_lines_binnmu()); + my @comments = grep(/^#/, @lines); + + is(@entries, MIN_NUM_ENTRIES); + is($entries[0], $entries_orig[1]); + is(@entries_old, MIN_NUM_ENTRIES); + cmp_ok(@comments, ">=", 1); + + is(@entries_nmu, 1); +}; + +# Test changelog with both recent and old entries + --no-trim +$years_after_cutoff = 1; +$years_of_changelog = 4; +install_changelog($years_after_cutoff, $years_of_changelog); +each_compat_subtest { + my @lines_orig = changelog_lines_pkg(); + ok(run_dh_tool("dh_installchangelogs", "--no-trim")); + my @lines = changelog_lines_installed(); + my @entries = dates_in_lines(@lines); + my @entries_old = grep { $_ < CUTOFF_DATE } @entries; + my @comments = grep(/^#/, @lines); + + is(@lines, @lines_orig); + cmp_ok(@entries, ">", 1); + cmp_ok(@entries_old, ">", 1); + is(@comments, 0); +}; + +# Test changelog with both recent and old entries + notrimdch +$years_after_cutoff = 1; +$years_of_changelog = 4; +install_changelog($years_after_cutoff, $years_of_changelog); +each_compat_subtest { + my @lines_orig = changelog_lines_pkg(); + $ENV{DEB_BUILD_OPTIONS} = "notrimdch"; + ok(run_dh_tool("dh_installchangelogs")); + my @lines = changelog_lines_installed(); + my @entries = dates_in_lines(@lines); + my @entries_old = grep { $_ < CUTOFF_DATE } @entries; + my @comments = grep(/^#/, @lines); + + is(@lines, @lines_orig); + cmp_ok(@entries, ">", 1); + cmp_ok(@entries_old, ">", 1); + is(@comments, 0); +}; + +unlink("${\TEST_DIR}/debian/changelog"); diff --git a/t/dh_installdocs/01-868204-ignore-broken-symlinks.t b/t/dh_installdocs/01-868204-ignore-broken-symlinks.t new file mode 100755 index 0000000..b9801d2 --- /dev/null +++ b/t/dh_installdocs/01-868204-ignore-broken-symlinks.t @@ -0,0 +1,30 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); + +plan(tests => 1); + +each_compat_subtest { + my ($compat) = @_; + # #868204 - dh_installdocs did not replace dangling symlink + make_path('debian/debhelper/usr/share/doc/debhelper'); + make_symlink_raw_target('../to/nowhere/bar', + 'debian/debhelper/usr/share/doc/debhelper/README.Debian'); + create_empty_file('debian/README.Debian'); + + ok(-l 'debian/debhelper/usr/share/doc/debhelper/README.Debian'); + ok(!-e 'debian/debhelper/usr/share/doc/debhelper/README.Debian'); + + ok(run_dh_tool('dh_installdocs')); + ok(!-l 'debian/debhelper/usr/share/doc/debhelper/README.Debian', "#868204 [${compat}]"); + ok(-f 'debian/debhelper/usr/share/doc/debhelper/README.Debian', "#868204 [${compat}]"); + remove_tree('debian/debhelper', 'debian/tmp'); +}; + diff --git a/t/dh_installdocs/debian/changelog b/t/dh_installdocs/debian/changelog new file mode 100644 index 0000000..5850f0e --- /dev/null +++ b/t/dh_installdocs/debian/changelog @@ -0,0 +1,5 @@ +foo (1.0-1) unstable; urgency=low + + * Initial release. (Closes: #XXXXXX) + + -- Test <testing@nowhere> Mon, 11 Jul 2016 18:10:59 +0200 diff --git a/t/dh_installdocs/debian/control b/t/dh_installdocs/debian/control new file mode 100644 index 0000000..7e9a228 --- /dev/null +++ b/t/dh_installdocs/debian/control @@ -0,0 +1,21 @@ +Source: foo +Section: misc +Priority: optional +Maintainer: Test <testing@nowhere> +Rules-Requires-Root: no +Standards-Version: 3.9.8 + +Package: foo +Architecture: all +Description: package foo + Package foo + +Package: bar +Architecture: all +Description: package bar + Package bar + +Package: baz +Architecture: all +Description: package baz + Package baz diff --git a/t/dh_installdocs/debian/copyright b/t/dh_installdocs/debian/copyright new file mode 100644 index 0000000..7e6ffb0 --- /dev/null +++ b/t/dh_installdocs/debian/copyright @@ -0,0 +1 @@ +Some test copyright file diff --git a/t/dh_installdocs/debian/docfile b/t/dh_installdocs/debian/docfile new file mode 100644 index 0000000..2719eec --- /dev/null +++ b/t/dh_installdocs/debian/docfile @@ -0,0 +1 @@ +This file must not be empty, or dh_installdocs won't install it. diff --git a/t/dh_installdocs/dh_installdocs.t b/t/dh_installdocs/dh_installdocs.t new file mode 100755 index 0000000..64f1254 --- /dev/null +++ b/t/dh_installdocs/dh_installdocs.t @@ -0,0 +1,75 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; + + +use File::Path qw(remove_tree); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; + +our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + debian/changelog + debian/control + debian/docfile + debian/copyright +)); + +plan(tests => 5); + + +my $NODOC_PROFILE = { + 'env' => { + 'DEB_BUILD_PROFILES' => 'nodoc', + }, +}; + +my $doc = "debian/docfile"; + +each_compat_subtest { + ok(run_dh_tool('dh_installdocs', '-pbar', $doc)); + ok(-e "debian/bar/usr/share/doc/bar/docfile"); + remove_tree(qw(debian/foo debian/bar debian/baz)); +}; + +each_compat_subtest { + #regression in debhelper 9.20160702 (#830309) + ok(run_dh_tool('dh_installdocs', '-pbaz', '--link-doc=foo', $doc)); + + ok(-l "debian/baz/usr/share/doc/baz"); + ok(readlink("debian/baz/usr/share/doc/baz") eq 'foo'); + ok(-e "debian/baz/usr/share/doc/foo/docfile"); + remove_tree(qw(debian/foo debian/bar debian/baz)); +}; + +each_compat_subtest { + ok(run_dh_tool('dh_installdocs', '-pfoo', '--link-doc=bar', $doc)); + + ok(-l "debian/foo/usr/share/doc/foo"); + ok(readlink("debian/foo/usr/share/doc/foo") eq 'bar'); + ok(-e "debian/foo/usr/share/doc/bar/docfile"); + remove_tree(qw(debian/foo debian/bar debian/baz)); +}; + +# ... and with nodoc + +each_compat_subtest { + # docs are ignored, but copyright file is still there + ok(run_dh_tool($NODOC_PROFILE, 'dh_installdocs', $doc)); + for my $pkg (qw(foo bar baz)) { + ok(! -e "debian/$pkg/usr/share/doc/$pkg/docfile"); + ok(-e "debian/$pkg/usr/share/doc/$pkg/copyright"); + } + remove_tree(qw(debian/foo debian/bar debian/baz)); +}; + +each_compat_subtest { + # docs are ignored, but symlinked doc dir is still there + ok(run_dh_tool($NODOC_PROFILE, 'dh_installdocs', '-pfoo', '--link-doc=bar', $doc)); + ok(-l "debian/foo/usr/share/doc/foo"); + ok(readlink("debian/foo/usr/share/doc/foo") eq 'bar'); + ok(! -e "debian/foo/usr/share/doc/bar/docfile"); + remove_tree(qw(debian/foo debian/bar debian/baz)); +}; + diff --git a/t/dh_installgsettings/debian/changelog b/t/dh_installgsettings/debian/changelog new file mode 100644 index 0000000..5850f0e --- /dev/null +++ b/t/dh_installgsettings/debian/changelog @@ -0,0 +1,5 @@ +foo (1.0-1) unstable; urgency=low + + * Initial release. (Closes: #XXXXXX) + + -- Test <testing@nowhere> Mon, 11 Jul 2016 18:10:59 +0200 diff --git a/t/dh_installgsettings/debian/control b/t/dh_installgsettings/debian/control new file mode 100644 index 0000000..c3cb827 --- /dev/null +++ b/t/dh_installgsettings/debian/control @@ -0,0 +1,17 @@ +Source: foo +Section: misc +Priority: optional +Maintainer: Test <testing@nowhere> +Standards-Version: 3.9.8 + +Package: has-settings +Architecture: all +Depends: ${misc:Depends} +Description: package has-settings + This package has a GSettings schema. + +Package: no-settings +Architecture: all +Depends: ${misc:Depends} +Description: package no-settings + This package doesn't have a GSettings schema. diff --git a/t/dh_installgsettings/dh_installgsettings.t b/t/dh_installgsettings/dh_installgsettings.t new file mode 100755 index 0000000..fe76e8d --- /dev/null +++ b/t/dh_installgsettings/dh_installgsettings.t @@ -0,0 +1,49 @@ +#!/usr/bin/perl +use strict; +use Test::More tests => 1; + +use autodie; +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); + +our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + debian/changelog + debian/control +)); + +my $SCHEMAS = 'usr/share/glib-2.0/schemas'; + +sub touch { + my $path = shift; + open(my $fh, '>>', $path); + close $fh; +} + +sub slurp { + my $path = shift; + local $/ = undef; + open(my $fh, '<', $path); + my $contents = <$fh>; + close $fh; + return $contents; +} + +each_compat_subtest { + make_path("debian/has-settings/$SCHEMAS"); + touch("debian/has-settings/$SCHEMAS/com.example.HasSettings.xml"); + make_path("debian/has-unimportant-settings/$SCHEMAS"); + touch("debian/no-settings.substvars"); + ok(run_dh_tool('dh_installgsettings', '-phas-settings'), 'run for has-settings'); + ok(run_dh_tool('dh_installgsettings', '-pno-settings'), 'run for no-settings'); + remove_tree(qw(debian/has-settings debian/has-unimportant-settings)); + like(slurp('debian/has-settings.substvars'), + qr{^misc:Depends=dconf-gsettings-backend \| gsettings-backend$}m, + 'has-settings should depend on a backend'); + unlike(slurp('debian/no-settings.substvars'), + qr{^misc:Depends=dconf-gsettings-backend \| gsettings-backend$}m, + 'no-settings should not depend on a backend'); +}; + diff --git a/t/dh_installinit/debian/bar.other.init b/t/dh_installinit/debian/bar.other.init new file mode 100644 index 0000000..ea948c5 --- /dev/null +++ b/t/dh_installinit/debian/bar.other.init @@ -0,0 +1,4 @@ +#!/bin/sh +cat << 'EOF' +I am init script to be installed into package "bar" into /etc/init.d/other path. +EOF
\ No newline at end of file diff --git a/t/dh_installinit/debian/changelog b/t/dh_installinit/debian/changelog new file mode 100644 index 0000000..5850f0e --- /dev/null +++ b/t/dh_installinit/debian/changelog @@ -0,0 +1,5 @@ +foo (1.0-1) unstable; urgency=low + + * Initial release. (Closes: #XXXXXX) + + -- Test <testing@nowhere> Mon, 11 Jul 2016 18:10:59 +0200 diff --git a/t/dh_installinit/debian/control b/t/dh_installinit/debian/control new file mode 100644 index 0000000..48d4de2 --- /dev/null +++ b/t/dh_installinit/debian/control @@ -0,0 +1,20 @@ +Source: foo +Section: misc +Priority: optional +Maintainer: Test <testing@nowhere> +Standards-Version: 3.9.8 + +Package: foo +Architecture: all +Description: package foo + Package foo + +Package: bar +Architecture: all +Description: package bar + Package bar + +Package: baz +Architecture: all +Description: package baz + Package baz diff --git a/t/dh_installinit/debian/foo.service b/t/dh_installinit/debian/foo.service new file mode 100644 index 0000000..aa21636 --- /dev/null +++ b/t/dh_installinit/debian/foo.service @@ -0,0 +1,5 @@ +[Unit] +Description=A unit + +[Service] +ExecStart=/bin/true diff --git a/t/dh_installinit/dh_installinit.t b/t/dh_installinit/dh_installinit.t new file mode 100755 index 0000000..7a7817c --- /dev/null +++ b/t/dh_installinit/dh_installinit.t @@ -0,0 +1,44 @@ +#!/usr/bin/perl +use strict; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); + +our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + debian/changelog + debian/control + debian/foo.service + debian/bar.other.init +)); + +plan(tests => 2); + +each_compat_up_to_and_incl_subtest(10, sub { + make_path(qw(debian/foo debian/bar debian/baz)); + ok(run_dh_tool('dh_installinit')); + ok(-e "debian/foo/lib/systemd/system/foo.service"); + ok(find_script('foo', 'postinst')); + ok(run_dh_tool('dh_clean')); + +}); + +each_compat_from_and_above_subtest(11, sub { + make_path(qw(debian/foo debian/bar debian/baz)); + + ok(run_dh_tool('dh_installinit')); + ok(run_dh_tool({'quiet' => 1}, 'dh_installinit', '--name=other')); + ok(! -e "debian/foo/lib/systemd/system/foo.service"); + ok(!find_script('foo', 'postinst')); + ok(run_dh_tool('dh_clean')); + + make_path(qw(debian/foo/lib/systemd/system/ debian/bar debian/baz)); + copy_file('debian/foo.service', 'debian/foo/lib/systemd/system/foo.service'); + ok(run_dh_tool('dh_installinit')); + ok(!find_script('foo', 'postinst')); + ok(run_dh_tool('dh_clean')); +}); + diff --git a/t/dh_installman/01-basics.t b/t/dh_installman/01-basics.t new file mode 100755 index 0000000..141059a --- /dev/null +++ b/t/dh_installman/01-basics.t @@ -0,0 +1,94 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); + +sub has_man_db_tool { + my ($tool) = @_; + open(my $old_stderr, '>&', *STDERR) or error("dup(STDERR, tmp_fd): $!"); + open(*STDERR, '>', '/dev/null') or error("re-open stderr as /dev/null: $!"); + + my $res = defined(`$tool --version`); + open(*STDERR, '>&', $old_stderr) or error("dup(tmp_fd, STDERR): $!"); + close($old_stderr); + return $res; +} + +if (has_man_db_tool('man') || has_man_db_tool('man-recode')) { + plan(tests => 2); +} else { + plan(skip_all => 'Test requires man or man-recode'); +} + +our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + manpage-uncompressed.pod + manpage-compressed.pod + manpage-perl.pod + libmanpage.so.1.2.3.pod + libmanpage.so.9.2.3 +)); + +each_compat_subtest { + my ($compat) = @_; + if (! -d 'generated-manpages') { + # Static data that can be reused. Generate only in the first test + make_path('generated-manpages'); + for my $basename (qw(manpage-uncompressed manpage-compressed manpage-perl libmanpage.so.1.2.3)) { + doit('pod2man', '--utf8', '-c', 'Debhelper', '-r', '1.0', "${basename}.pod", + "generated-manpages/${basename}.1"); + } + doit('pod2man', '--utf8', '-c', 'Debhelper', '-r', '1.0', '-s', '3', 'manpage-perl.pod', + 'generated-manpages/manpage-perl.3perl'); + doit('gzip', '-9n', 'generated-manpages/manpage-compressed.1'); + } + ok(run_dh_tool('dh_installman', 'generated-manpages/manpage-uncompressed.1', + 'generated-manpages/manpage-compressed.1.gz', + 'generated-manpages/manpage-perl.3perl', + 'generated-manpages/libmanpage.so.1.2.3.1', + 'libmanpage.so.9.2.3')); + + ok(-e 'debian/debhelper/usr/share/man/man1/manpage-uncompressed.1'); + ok(-e 'debian/debhelper/usr/share/man/man1/manpage-compressed.1'); + ok(-e 'debian/debhelper/usr/share/man/man3/manpage-perl.3'); + ok(-e 'debian/debhelper/usr/share/man/man1/libmanpage.so.1.2.3.1'); + ok(! -e 'debian/debhelper/usr/share/man/man9/libmanpage.so.9.2.9.2.3'); + ok(-l 'debian/debhelper/usr/share/man/man3/libmanpage.so.9.2.3'); + remove_tree('debian/debhelper', 'debian/tmp', 'debian/.debhelper'); +}; + +each_compat_subtest { + my ($compat) = @_; + if (! -d 'generated-manpages') { + # Static data that can be reused. Generate only in the first test + make_path('generated-manpages'); + for my $basename (qw(manpage-uncompressed manpage-compressed libmanpage.so.1.2.3)) { + doit('pod2man', '--utf8', '-c', 'Debhelper', '-r', '1.0', "${basename}.pod", + "generated-manpages/${basename}.1"); + } + doit('pod2man', '--utf8', '-c', 'Debhelper', '-r', '1.0', '-s', '3', 'manpage-perl.pod', + 'generated-manpages/manpage-perl.3perl'); + doit('gzip', '-9n', 'generated-manpages/manpage-compressed.1'); + } + mkdirs('debian/debhelper/usr/share/man/man1'); + mkdirs('debian/debhelper/usr/share/man/man3'); + copy_file('generated-manpages/manpage-uncompressed.1', 'debian/debhelper/usr/share/man/man1/manpage-uncompressed.1'); + copy_file('generated-manpages/manpage-compressed.1.gz', 'debian/debhelper/usr/share/man/man1/manpage-compressed.1.gz'); + copy_file('generated-manpages/manpage-perl.3perl', 'debian/debhelper/usr/share/man/man3/manpage-perl.3perl'); + copy_file('generated-manpages/libmanpage.so.1.2.3.1', 'debian/debhelper/usr/share/man/man1/libmanpage.so.1.2.3.1'); + copy_file('libmanpage.so.9.2.3', 'debian/debhelper/usr/share/man/man3/libmanpage.so.9.2.3'); + ok(run_dh_tool('dh_installman')); + ok(-e 'debian/debhelper/usr/share/man/man1/manpage-uncompressed.1'); + ok(-e 'debian/debhelper/usr/share/man/man1/manpage-compressed.1'); + ok(-e 'debian/debhelper/usr/share/man/man3/manpage-perl.3perl'); + ok(-e 'debian/debhelper/usr/share/man/man1/libmanpage.so.1.2.3.1'); + ok(! -e 'debian/debhelper/usr/share/man/man9/libmanpage.so.9.2.9.2.3'); + ok(-l 'debian/debhelper/usr/share/man/man3/libmanpage.so.9.2.3'); + remove_tree('debian/debhelper', 'debian/tmp', 'debian/.debhelper'); +}; + diff --git a/t/dh_installman/libmanpage.so.1.2.3.pod b/t/dh_installman/libmanpage.so.1.2.3.pod new file mode 100644 index 0000000..0b68dec --- /dev/null +++ b/t/dh_installman/libmanpage.so.1.2.3.pod @@ -0,0 +1,17 @@ +=head1 NAME + +libmanpage.so.1.2.3 - Something very exciting + +=head1 SYNOPSIS + +This tool does not exist but would be awesome. + +=head1 SEE ALSO + +L<debhelper(7)> + +=head1 AUTHORS + +Niels Thykier <niels@thykier.net> + +=cut diff --git a/t/dh_installman/libmanpage.so.9.2.3 b/t/dh_installman/libmanpage.so.9.2.3 new file mode 100644 index 0000000..07658f3 --- /dev/null +++ b/t/dh_installman/libmanpage.so.9.2.3 @@ -0,0 +1 @@ +.so man1/manpage-uncompressed.1 diff --git a/t/dh_installman/manpage-compressed.pod b/t/dh_installman/manpage-compressed.pod new file mode 100644 index 0000000..d2c0596 --- /dev/null +++ b/t/dh_installman/manpage-compressed.pod @@ -0,0 +1,17 @@ +=head1 NAME + +manpage - Something very exciting + +=head1 SYNOPSIS + +This tool does not exist but would be awesome. + +=head1 SEE ALSO + +L<debhelper(7)> + +=head1 AUTHORS + +Niels Thykier <niels@thykier.net> + +=cut diff --git a/t/dh_installman/manpage-perl.pod b/t/dh_installman/manpage-perl.pod new file mode 100644 index 0000000..9b66d9d --- /dev/null +++ b/t/dh_installman/manpage-perl.pod @@ -0,0 +1,17 @@ +=head3 NAME + +manpage-uncompressed - Something very exciting + +=head3 SYNOPSIS + +This tool does not exist but would be awesome. + +=head3 SEE ALSO + +L<debhelper(7)> + +=head3 AUTHORS + +Niels Thykier <niels@thykier.net> + +=cut diff --git a/t/dh_installman/manpage-uncompressed.pod b/t/dh_installman/manpage-uncompressed.pod new file mode 100644 index 0000000..c95037c --- /dev/null +++ b/t/dh_installman/manpage-uncompressed.pod @@ -0,0 +1,17 @@ +=head1 NAME + +manpage-uncompressed - Something very exciting + +=head1 SYNOPSIS + +This tool does not exist but would be awesome. + +=head1 SEE ALSO + +L<debhelper(7)> + +=head1 AUTHORS + +Niels Thykier <niels@thykier.net> + +=cut diff --git a/t/dh_installpam/debian/changelog b/t/dh_installpam/debian/changelog new file mode 100644 index 0000000..5850f0e --- /dev/null +++ b/t/dh_installpam/debian/changelog @@ -0,0 +1,5 @@ +foo (1.0-1) unstable; urgency=low + + * Initial release. (Closes: #XXXXXX) + + -- Test <testing@nowhere> Mon, 11 Jul 2016 18:10:59 +0200 diff --git a/t/dh_installpam/debian/control b/t/dh_installpam/debian/control new file mode 100644 index 0000000..c266f51 --- /dev/null +++ b/t/dh_installpam/debian/control @@ -0,0 +1,10 @@ +Source: foo +Section: misc +Priority: optional +Maintainer: Test <testing@example.org> +Standards-Version: 3.9.8 + +Package: foo +Architecture: all +Description: package foo + Package foo diff --git a/t/dh_installpam/debian/foo.pam b/t/dh_installpam/debian/foo.pam new file mode 100644 index 0000000..fab1c8c --- /dev/null +++ b/t/dh_installpam/debian/foo.pam @@ -0,0 +1 @@ +@include common-auth diff --git a/t/dh_installpam/dh_installpam.t b/t/dh_installpam/dh_installpam.t new file mode 100755 index 0000000..4e76799 --- /dev/null +++ b/t/dh_installpam/dh_installpam.t @@ -0,0 +1,38 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use Test::More; +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); + +plan(tests => 2); + +our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + debian/changelog + debian/control + debian/foo.pam +)); + +each_compat_up_to_and_incl_subtest(13, sub { + make_path(qw(debian/foo)); + ok(run_dh_tool('dh_installpam')); + + ok(-f 'debian/foo/etc/pam.d/foo'); + ok(! -f 'debian/foo/usr/lib/pam.d/foo'); + + ok(run_dh_tool('dh_clean')); +}); + +each_compat_from_and_above_subtest(14, sub { + make_path(qw(debian/foo)); + ok(run_dh_tool('dh_installpam')); + + ok(! -f 'debian/foo/etc/pam.d/foo'); + ok(-f 'debian/foo/usr/lib/pam.d/foo'); + + ok(run_dh_tool('dh_clean')); +}); diff --git a/t/dh_installsystemd/debian/changelog b/t/dh_installsystemd/debian/changelog new file mode 100644 index 0000000..5850f0e --- /dev/null +++ b/t/dh_installsystemd/debian/changelog @@ -0,0 +1,5 @@ +foo (1.0-1) unstable; urgency=low + + * Initial release. (Closes: #XXXXXX) + + -- Test <testing@nowhere> Mon, 11 Jul 2016 18:10:59 +0200 diff --git a/t/dh_installsystemd/debian/control b/t/dh_installsystemd/debian/control new file mode 100644 index 0000000..48d4de2 --- /dev/null +++ b/t/dh_installsystemd/debian/control @@ -0,0 +1,20 @@ +Source: foo +Section: misc +Priority: optional +Maintainer: Test <testing@nowhere> +Standards-Version: 3.9.8 + +Package: foo +Architecture: all +Description: package foo + Package foo + +Package: bar +Architecture: all +Description: package bar + Package bar + +Package: baz +Architecture: all +Description: package baz + Package baz diff --git a/t/dh_installsystemd/debian/foo.init b/t/dh_installsystemd/debian/foo.init new file mode 100644 index 0000000..2b77921 --- /dev/null +++ b/t/dh_installsystemd/debian/foo.init @@ -0,0 +1,4 @@ +#!/bin/sh + +some script + diff --git a/t/dh_installsystemd/debian/foo.service b/t/dh_installsystemd/debian/foo.service new file mode 100644 index 0000000..2b48a78 --- /dev/null +++ b/t/dh_installsystemd/debian/foo.service @@ -0,0 +1,8 @@ +[Unit] +Description=A unit + +[Service] +ExecStart=/bin/true + +[Install] +WantedBy=multi-user.target diff --git a/t/dh_installsystemd/debian/foo2.service b/t/dh_installsystemd/debian/foo2.service new file mode 100644 index 0000000..42b9445 --- /dev/null +++ b/t/dh_installsystemd/debian/foo2.service @@ -0,0 +1,8 @@ +[Unit] +Description=Another unit + +[Service] +ExecStart=/bin/true + +[Install] +WantedBy=multi-user.target diff --git a/t/dh_installsystemd/dh_installsystemd.t b/t/dh_installsystemd/dh_installsystemd.t new file mode 100755 index 0000000..bbb4eb0 --- /dev/null +++ b/t/dh_installsystemd/dh_installsystemd.t @@ -0,0 +1,255 @@ +#!/usr/bin/perl +use strict; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); + +plan(tests => 4); + +sub write_file { + my ($path, $content) = @_; + + my $dir = dirname($path); + mkdirs($dir); + + open(my $fd, '>>', $path) or error("open($path) failed: $!"); + print {$fd} $content . '\n'; + close($fd) or error("close($path) failed: $!"); +} + +sub unit_is_enabled { + my ($package, $unit, $num_enables) = @_; + my @output; + my $matches; + my @postinst_snippets = find_script($package, 'postinst'); + @output=`cat @postinst_snippets` if @postinst_snippets; + # Match exactly one tab; the "dont-enable" script has an "enable" + # line for re-enabling the service if the admin had it enabled. + # But we do not want to include that in our count. + $matches = grep { m{^\tif deb-systemd-helper .* was-enabled .*'\Q$unit\E\.service'} } @output; + ok($matches == $num_enables) or diag("$unit appears to have been enabled $matches times (expected $num_enables)"); +} + +sub unit_is_started { + my ($package, $unit, $num_starts, $num_stops) = @_; + my @output; + my $matches; + $num_stops = $num_stops // $num_starts; + my @postinst_snippets = find_script($package, 'postinst'); + @output=`cat @postinst_snippets` if @postinst_snippets; + $matches = grep { m{deb-systemd-invoke \$_dh_action .*'\Q$unit\E.service'} } @output; + ok($matches == $num_starts) or diag("$unit appears to have been started $matches times (expected $num_starts)"); + my @prerm_snippets = find_script($package, 'prerm'); + @output=`cat @prerm_snippets` if @prerm_snippets; + $matches = grep { m{deb-systemd-invoke stop .*'\Q$unit\E.service'} } @output; + ok($matches == $num_stops) or diag("$unit appears to have been stopped $matches times (expected $num_stops)"); +} + + +# +# Test a simple source package defining a single binary package +# +our $TEST_DH_FIXTURE_DIR = 'simple'; +our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + debian/changelog + debian/control + debian/foo.service +)); + +each_compat_subtest { + ok(run_dh_tool('dh_installsystemd')); + ok(-e 'debian/foo/lib/systemd/system/foo.service'); + ok(find_script('foo', 'postinst')); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 1); + ok(run_dh_tool('dh_clean')); + + ok(run_dh_tool('dh_installsystemd', '--no-start')); + ok(-e 'debian/foo/lib/systemd/system/foo.service'); + ok(find_script('foo', 'postinst')); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 0, 0); + ok(run_dh_tool('dh_clean')); + + ok(run_dh_tool('dh_installsystemd', '--no-start', 'foo.service')); + ok(-e 'debian/foo/lib/systemd/system/foo.service'); + ok(find_script('foo', 'postinst')); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 0, 0); + ok(run_dh_tool('dh_clean')); +}; + + +# +# Test a more complex source package defining three binary packages +# +$TEST_DH_FIXTURE_DIR = '.'; +@TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + debian/changelog + debian/control + debian/foo.service + debian/foo2.service +)); + +each_compat_subtest { + ok(run_dh_tool( 'dh_installsystemd')); + ok(-e 'debian/foo/lib/systemd/system/foo.service'); + ok(find_script('foo', 'postinst')); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 1); + unit_is_enabled('foo', 'foo2', 0); + unit_is_started('foo', 'foo2', 0); + ok(run_dh_tool('dh_clean')); + + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo2.service', 'debian/foo/lib/systemd/system/foo2.service'); + ok(run_dh_tool('dh_installsystemd')); + ok(-e 'debian/foo/lib/systemd/system/foo.service'); + ok(find_script('foo', 'postinst')); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 1); + unit_is_enabled('foo', 'foo2', 1); + unit_is_started('foo', 'foo2', 1); + ok(run_dh_tool('dh_clean')); + + + # lib -> usr/lib (if we ever support that) + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo2.service', 'debian/foo/lib/systemd/system/foo2.service'); + ok(run_dh_tool('dh_installsystemd')); + ok(-e 'debian/foo/lib/systemd/system/foo2.service'); + ok(find_script('foo', 'postinst')); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 1); + unit_is_enabled('foo', 'foo2', 1); + unit_is_started('foo', 'foo2', 1); + ok(run_dh_tool('dh_clean')); + + # lib -> usr/lib with both no-empty (if we ever suport that) + make_path('debian/foo/lib/systemd/system/'); + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo2.service', 'debian/foo/lib/systemd/system/foo2.service'); + copy_file('debian/foo2.service', 'debian/foo/lib/systemd/system/bar.service'); + ok(run_dh_tool('dh_installsystemd')); + ok(-e 'debian/foo/lib/systemd/system/bar.service'); + ok(-e 'debian/foo/lib/systemd/system/foo2.service'); + ok(find_script('foo', 'postinst')); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 1); + unit_is_enabled('foo', 'foo2', 1); + unit_is_started('foo', 'foo2', 1); + ok(run_dh_tool('dh_clean')); + + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo2.service', 'debian/foo/lib/systemd/system/foo2.service'); + ok(run_dh_tool('dh_installsystemd', '--no-start')); + ok(-e 'debian/foo/lib/systemd/system/foo.service'); + ok(find_script('foo', 'postinst')); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 0, 0); + unit_is_enabled('foo', 'foo2', 1); + unit_is_started('foo', 'foo2', 0, 0); + ok(run_dh_tool('dh_clean')); + + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo2.service', 'debian/foo/lib/systemd/system/foo2.service'); + ok(run_dh_tool('dh_installsystemd', '-p', 'foo', '--no-start', 'foo.service')); + ok(run_dh_tool('dh_installsystemd', '-p', 'foo', 'foo2.service')); + ok(-e 'debian/foo/lib/systemd/system/foo.service'); + ok(find_script('foo', 'postinst')); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 0, 0); + unit_is_enabled('foo', 'foo2', 1); + unit_is_started('foo', 'foo2', 1); + ok(run_dh_tool('dh_clean')); + + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo2.service', 'debian/foo/lib/systemd/system/foo2.service'); + ok(run_dh_tool('dh_installsystemd', '-p', 'foo', '--no-enable', 'foo.service')); + ok(run_dh_tool('dh_installsystemd', '-p', 'foo', 'foo2.service')); + ok(-e 'debian/foo/lib/systemd/system/foo.service'); + ok(find_script('foo', 'postinst')); + unit_is_enabled('foo', 'foo', 0); + unit_is_started('foo', 'foo', 1, 1); + unit_is_enabled('foo', 'foo2', 1); + unit_is_started('foo', 'foo2', 1); + ok(run_dh_tool('dh_clean')); + + make_path('debian/foo/lib/systemd/system/'); + ok(run_dh_tool('dh_installsystemd', '--no-restart-after-upgrade')); + my @foo_postinst = find_script('foo', 'postinst'); + ok(@foo_postinst); + my $matches = @foo_postinst ? grep { m{deb-systemd-invoke start .*foo.service} } `cat @foo_postinst` : -1; + ok($matches == 1); + ok(run_dh_tool('dh_clean')); + + # Quoting #764730 + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo.service', 'debian/foo/lib/systemd/system/foo\x2dfuse.service'); + ok(run_dh_tool('dh_installsystemd')); + unit_is_enabled('foo', 'foo\x2dfuse', 1); + unit_is_started('foo', 'foo\x2dfuse', 1); + ok(run_dh_tool('dh_clean')); + + # --name flag #870768 + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo2.service', 'debian/foo/lib/systemd/system/foo2.service'); + ok(run_dh_tool('dh_installsystemd', '--name=foo')); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 1); + unit_is_enabled('foo', 'foo2', 0); + unit_is_started('foo', 'foo2', 0); + ok(run_dh_tool('dh_installsystemd', '--name=foo2')); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 1); + unit_is_enabled('foo', 'foo2', 1); + unit_is_started('foo', 'foo2', 1); + ok(run_dh_tool('dh_clean')); + + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo.service', 'debian/foo/lib/systemd/system/target.service'); + make_symlink_raw_target('target.service', 'debian/foo/lib/systemd/system/source.service'); + ok(run_dh_tool('dh_installsystemd')); + unit_is_enabled('foo', 'foo', 1); + # Alias= realized by symlinks are not enabled in maintaner scripts + unit_is_enabled('foo', 'source', 0); + unit_is_enabled('foo', 'target', 1); + ok(run_dh_tool('dh_clean')); +}; + +each_compat_up_to_and_incl_subtest(11, sub { + make_path('debian/foo/lib/systemd/system/'); + make_path('debian/foo/etc/init.d/'); + copy_file('debian/foo.service', 'debian/foo/lib/systemd/system/target.service'); + make_symlink_raw_target('target.service', 'debian/foo/lib/systemd/system/source.service'); + write_file('debian/foo/etc/init.d/source', '# something'); + ok(run_dh_tool('dh_installsystemd')); + unit_is_enabled('foo', 'foo', 1); + # Alias= realized by symlinks are not enabled in maintaner scripts + unit_is_enabled('foo', 'source', 0); + unit_is_enabled('foo', 'target', 1); + # The presence of a sysvinit script for the alias unit inhibits start of both + unit_is_started('foo', 'source', 0); + unit_is_started('foo', 'target', 0); + ok(run_dh_tool('dh_clean')); +}); + +each_compat_from_and_above_subtest(12, sub { + make_path('debian/foo/lib/systemd/system/'); + make_path('debian/foo/etc/init.d/'); + copy_file('debian/foo.service', 'debian/foo/lib/systemd/system/target.service'); + make_symlink_raw_target('target.service', 'debian/foo/lib/systemd/system/source.service'); + write_file('debian/foo/etc/init.d/source', '# something'); + ok(run_dh_tool('dh_installsystemd')); + unit_is_enabled('foo', 'foo', 1); + # Alias= realized by symlinks are not enabled in maintaner scripts + unit_is_enabled('foo', 'source', 0); + unit_is_enabled('foo', 'target', 1); + unit_is_started('foo', 'source', 0); + unit_is_started('foo', 'target', 1); + ok(run_dh_tool('dh_clean')); +}); diff --git a/t/dh_installsystemd/dh_installsystemd_tmpfiles.t b/t/dh_installsystemd/dh_installsystemd_tmpfiles.t new file mode 100755 index 0000000..0fffe57 --- /dev/null +++ b/t/dh_installsystemd/dh_installsystemd_tmpfiles.t @@ -0,0 +1,87 @@ +#!/usr/bin/perl +use strict; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); + +our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + debian/changelog + debian/control + debian/foo.service + debian/foo.init +)); + +plan(tests => 3); + + +# Units are installed and enabled +each_compat_from_x_to_and_incl_y_subtest(11, 12, sub { + make_path('debian/foo/usr/lib/tmpfiles.d'); + create_empty_file('debian/foo/usr/lib/tmpfiles.d/foo.conf'); + ok(run_dh_tool('dh_installinit')); + ok(run_dh_tool('dh_installsystemd')); + ok(-e "debian/foo/etc/init.d/foo"); + ok(-e "debian/foo/lib/systemd/system/foo.service"); + my @postinst = find_script('foo', 'postinst'); + # We should have two snippets (one for the tmpfiles and one for the services). + is(scalar(@postinst), 2); + if (scalar(@postinst) == 2) { + open(my $fd, '<', $postinst[0]) or error("open($postinst[0]) failed: $!"); + my $early_snippet = readlines($fd); + close($fd); + open($fd, '<', $postinst[1]) or error("open($postinst[1]) failed: $!"); + my $late_snippet = readlines($fd); + close($fd); + ok(! grep { m/(?:invoke|update)-rc.d|deb-systemd-invoke/ } @{$early_snippet}); + ok(grep { m/(?:invoke|update)-rc.d|deb-systemd-invoke/ } @{$late_snippet}); + ok(grep { m/systemd-tmpfiles/ } @{$early_snippet}); + ok(! grep { m/systemd-tmpfiles/ } @{$late_snippet}); + } + ok(run_dh_tool('dh_clean')); + +}); + +each_compat_from_and_above_subtest(13, sub { + make_path('debian/foo/usr/lib/tmpfiles.d'); + create_empty_file('debian/foo/usr/lib/tmpfiles.d/foo.conf'); + ok(run_dh_tool('dh_installinit')); + ok(run_dh_tool('dh_installsystemd')); + ok(-e "debian/foo/etc/init.d/foo"); + ok(-e "debian/foo/lib/systemd/system/foo.service"); + my @postinst = find_script('foo', 'postinst'); + # We should have one snippet (one for the services). + is(scalar(@postinst), 1); + if (scalar(@postinst) == 1) { + open(my $fd, '<', $postinst[0]) or error("open($postinst[0]) failed: $!"); + my $snippet = readlines($fd); + close($fd); + ok(grep { m/(?:invoke|update)-rc.d|deb-systemd-invoke/ } @{$snippet}); + ok(! grep { m/systemd-tmpfiles/ } @{$snippet}); + } + ok(run_dh_tool('dh_clean')); +}); + + +each_compat_from_and_above_subtest(13, sub { + make_path('debian/foo/usr/lib/tmpfiles.d'); + create_empty_file('debian/foo/usr/lib/tmpfiles.d/foo.conf'); + ok(run_dh_tool('dh_installtmpfiles')); + # dh_installtmpfiles do not install services + ok(!-e "debian/foo/etc/init.d/foo"); + ok(!-e "debian/foo/lib/systemd/system/foo.service"); + my @postinst = find_script('foo', 'postinst'); + # We should have too snippets (one for the tmpfiles and one for the services). + is(scalar(@postinst), 1); + if (scalar(@postinst) == 1) { + open(my $fd, '<', $postinst[0]) or error("open($postinst[0]) failed: $!"); + my $snippet = readlines($fd); + close($fd); + ok(! grep { m/(?:invoke|update)-rc.d|deb-systemd-invoke/ } @{$snippet}); + ok(grep { m/systemd-tmpfiles/ } @{$snippet}); + } + ok(run_dh_tool('dh_clean')); +}); diff --git a/t/dh_installsystemd/dh_systemd.t b/t/dh_installsystemd/dh_systemd.t new file mode 100755 index 0000000..c3c9401 --- /dev/null +++ b/t/dh_installsystemd/dh_systemd.t @@ -0,0 +1,123 @@ +#!/usr/bin/perl +use strict; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); + +our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + debian/changelog + debian/control + debian/foo.service + debian/foo2.service +)); + +plan(tests => 1); + +sub unit_is_enabled { + my ($package, $unit, $num_enables) = @_; + my @output; + my $matches; + @output=`cat debian/$package.postinst.debhelper`; + # Match exactly one tab; the "dont-enable" script has an "enable" + # line for re-enabling the service if the admin had it enabled. + # But we do not want to include that in our count. + $matches = grep { m{^\tif deb-systemd-helper .* was-enabled .*'\Q$unit\E\.service'} } @output; + ok($matches == $num_enables) or diag("$unit appears to have been enabled $matches times (expected $num_enables)"); +} +sub unit_is_started { + my ($package, $unit, $num_starts, $num_stops) = @_; + my @output; + my $matches; + $num_stops = $num_stops // $num_starts; + @output=`cat debian/$package.postinst.debhelper`; + $matches = grep { m{deb-systemd-invoke \$_dh_action .*'\Q$unit\E.service'} } @output; + ok($matches == $num_starts) or diag("$unit appears to have been started $matches times (expected $num_starts)"); + @output=`cat debian/$package.prerm.debhelper`; + $matches = grep { m{deb-systemd-invoke stop .*'\Q$unit\E.service'} } @output; + ok($matches == $num_stops) or diag("$unit appears to have been stopped $matches times (expected $num_stops)"); +} + +# Units are installed and enabled +each_compat_from_x_to_and_incl_y_subtest(10, 10, sub { + ok(run_dh_tool('dh_systemd_enable')); + ok(run_dh_tool('dh_systemd_start')); + ok(-e "debian/foo/lib/systemd/system/foo.service"); + ok(-e "debian/foo.postinst.debhelper"); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 1); + unit_is_enabled('foo', 'foo2', 0); + unit_is_started('foo', 'foo2', 0); + ok(run_dh_tool('dh_clean')); + + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo2.service', 'debian/foo/lib/systemd/system/foo2.service'); + ok(run_dh_tool('dh_systemd_enable')); + ok(run_dh_tool('dh_systemd_start')); + ok(-e "debian/foo/lib/systemd/system/foo.service"); + ok(-e "debian/foo.postinst.debhelper"); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 1); + unit_is_enabled('foo', 'foo2', 1); + unit_is_started('foo', 'foo2', 1); + ok(run_dh_tool('dh_clean')); + + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo2.service', 'debian/foo/lib/systemd/system/foo2.service'); + ok(run_dh_tool('dh_systemd_enable')); + ok(run_dh_tool('dh_systemd_start', '--no-start')); + ok(-e "debian/foo/lib/systemd/system/foo.service"); + ok(-e "debian/foo.postinst.debhelper"); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 0, 1); # present units are stopped on remove even if no start + unit_is_enabled('foo', 'foo2', 1); + unit_is_started('foo', 'foo2', 0, 1); + ok(run_dh_tool('dh_clean')); + + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo2.service', 'debian/foo/lib/systemd/system/foo2.service'); + ok(run_dh_tool('dh_systemd_enable')); + ok(run_dh_tool('dh_systemd_start', '--no-start', 'debian/foo.service')); + ok(run_dh_tool('dh_systemd_start', '-p', 'foo', 'foo2.service')); + ok(-e "debian/foo/lib/systemd/system/foo.service"); + ok(-e "debian/foo.postinst.debhelper"); + unit_is_enabled('foo', 'foo', 1); + unit_is_started('foo', 'foo', 0, 1); + unit_is_enabled('foo', 'foo2', 1); + unit_is_started('foo', 'foo2', 1); + ok(run_dh_tool('dh_clean')); + + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo2.service', 'debian/foo/lib/systemd/system/foo2.service'); + ok(run_dh_tool('dh_systemd_enable', '--no-enable', 'debian/foo.service')); + ok(run_dh_tool('dh_systemd_enable', '-p', 'foo', 'foo2.service')); + ok(run_dh_tool('dh_systemd_start')); + ok(-e "debian/foo/lib/systemd/system/foo.service"); + ok(-e "debian/foo.postinst.debhelper"); + unit_is_enabled('foo', 'foo', 0); + unit_is_started('foo', 'foo', 1, 1); + unit_is_enabled('foo', 'foo2', 1); + unit_is_started('foo', 'foo2', 1); + ok(run_dh_tool('dh_clean')); + + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo.service', 'debian/foo/lib/systemd/system/foo.service'); + ok(run_dh_tool('dh_systemd_start', '--no-restart-after-upgrade')); + my $matches = grep { m{deb-systemd-invoke start .*foo.service} } `cat debian/foo.postinst.debhelper`; + ok($matches == 1); + ok(run_dh_tool('dh_clean')); + + # Quoting #764730 + make_path('debian/foo/lib/systemd/system/'); + copy_file('debian/foo.service', 'debian/foo/lib/systemd/system/foo\x2dfuse.service'); + ok(run_dh_tool('dh_systemd_enable')); + ok(run_dh_tool('dh_systemd_start')); + unit_is_enabled('foo', 'foo\x2dfuse', 1); + unit_is_started('foo', 'foo\x2dfuse', 1); + ok(run_dh_tool('dh_clean')); +}); + + diff --git a/t/dh_installsystemd/simple/debian/changelog b/t/dh_installsystemd/simple/debian/changelog new file mode 100644 index 0000000..5b1a8fe --- /dev/null +++ b/t/dh_installsystemd/simple/debian/changelog @@ -0,0 +1,5 @@ +foo (1.0-1) unstable; urgency=low + + * Initial release. (Closes: #XXXXXX) + + -- Test <test@example.org> Mon, 11 Jul 2016 18:10:59 +0200 diff --git a/t/dh_installsystemd/simple/debian/control b/t/dh_installsystemd/simple/debian/control new file mode 100644 index 0000000..4f4238e --- /dev/null +++ b/t/dh_installsystemd/simple/debian/control @@ -0,0 +1,10 @@ +Source: foo +Section: misc +Priority: optional +Maintainer: Test <testing@nowhere> +Standards-Version: 3.9.8 + +Package: foo +Architecture: all +Description: package foo + Package foo diff --git a/t/dh_installsystemd/simple/debian/foo.service b/t/dh_installsystemd/simple/debian/foo.service new file mode 100644 index 0000000..2b48a78 --- /dev/null +++ b/t/dh_installsystemd/simple/debian/foo.service @@ -0,0 +1,8 @@ +[Unit] +Description=A unit + +[Service] +ExecStart=/bin/true + +[Install] +WantedBy=multi-user.target diff --git a/t/dh_installsystemduser/debian/baz.user.service b/t/dh_installsystemduser/debian/baz.user.service new file mode 100644 index 0000000..3af041d --- /dev/null +++ b/t/dh_installsystemduser/debian/baz.user.service @@ -0,0 +1,8 @@ +[Unit] +Description=Baz User Unit + +[Service] +ExecStart=/bin/true + +[Install] +WantedBy=default.target diff --git a/t/dh_installsystemduser/debian/changelog b/t/dh_installsystemduser/debian/changelog new file mode 100644 index 0000000..5850f0e --- /dev/null +++ b/t/dh_installsystemduser/debian/changelog @@ -0,0 +1,5 @@ +foo (1.0-1) unstable; urgency=low + + * Initial release. (Closes: #XXXXXX) + + -- Test <testing@nowhere> Mon, 11 Jul 2016 18:10:59 +0200 diff --git a/t/dh_installsystemduser/debian/control b/t/dh_installsystemduser/debian/control new file mode 100644 index 0000000..adccbc6 --- /dev/null +++ b/t/dh_installsystemduser/debian/control @@ -0,0 +1,10 @@ +Source: foo +Section: misc +Priority: optional +Maintainer: Test <testing@exampe.org> +Standards-Version: 3.9.8 + +Package: foo +Architecture: all +Description: package foo + Package foo diff --git a/t/dh_installsystemduser/debian/foo.user.service b/t/dh_installsystemduser/debian/foo.user.service new file mode 100644 index 0000000..7ef597d --- /dev/null +++ b/t/dh_installsystemduser/debian/foo.user.service @@ -0,0 +1,8 @@ +[Unit] +Description=Foo User Unit + +[Service] +ExecStart=/bin/true + +[Install] +WantedBy=default.target diff --git a/t/dh_installsystemduser/dh_installsystemduser.t b/t/dh_installsystemduser/dh_installsystemduser.t new file mode 100755 index 0000000..5171728 --- /dev/null +++ b/t/dh_installsystemduser/dh_installsystemduser.t @@ -0,0 +1,112 @@ +#!/usr/bin/perl +use strict; +use Test::More; +use File::Path qw(make_path); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use Debian::Debhelper::Dh_Lib qw(!dirname); + +plan(tests => 1); + +our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + debian/changelog + debian/control + debian/foo.user.service + debian/baz.user.service +)); + + +sub read_script { + my ($package, $name) = @_; + my @lines; + + foreach my $script (find_script($package, $name)) { + open(my $fh, '<', $script) or die("open($script): $!"); + push @lines, $_ for <$fh>; + close($fh); + } + + return @lines; +} + +sub _unit_check_user_enabled { + my ($package, $unit, $enabled) = @_; + my $verb = $enabled ? "is" : "isnt"; + my $matches; + + my @postinst = read_script($package, 'postinst'); + # Match exactly two tab character. The "dont-enable" script has + # an "enable" line for re-enabling the service if the admin had it + # enabled, but we do not want to include that in our count. + $matches = grep { m{^\t\tif deb-systemd-helper( --\w+)* --user was-enabled.*'\Q$unit'} } @postinst; + is($matches, $enabled, "$unit $verb enabled"); +} + +sub _unit_check_user_started { + my ($package, $unit, $started) = @_; + my $verb = $started ? "is" : "isnt"; + my $matches; + + my @postinst = read_script($package, 'postinst'); + # Match exactly two tab character. The "dont-enable" script has + # an "enable" line for re-enabling the service if the admin had it + # enabled, but we do not want to include that in our count. + $matches = grep { m{deb-systemd-invoke --user restart.*'\Q$unit'} } @postinst; + is($matches, $started, "$unit $verb started"); + + my @prerm = read_script($package, 'prerm'); + $matches = grep { m{deb-systemd-invoke --user stop.*'\Q$unit'} } @prerm; + is($matches, $started, "$unit $verb stopped"); +} + +sub is_enabled { _unit_check_user_enabled(@_, 1); } +sub isnt_enabled { _unit_check_user_enabled(@_, 0); } +sub is_started { _unit_check_user_started(@_, 1); } +sub isnt_started { _unit_check_user_started(@_, 0); } + +each_compat_subtest { + my ($compat) = @_; + make_path('debian/foo/usr/lib/systemd/user/'); + copy_file('debian/foo.user.service', 'debian/foo/usr/lib/systemd/user/bar.service'); + ok(run_dh_tool('dh_installsystemduser')); + ok(-e 'debian/foo/usr/lib/systemd/user/foo.service'); + is_enabled('foo', 'foo.service'); + is_enabled('foo', 'bar.service'); + if ($compat > 13) { + is_started('foo', 'foo.service'); + is_started('foo', 'bar.service'); + } else { + isnt_started('foo', 'foo.service'); + isnt_started('foo', 'bar.service'); + } + ok(run_dh_tool('dh_clean')); + + ok(run_dh_tool('dh_installsystemduser')); + ok(-e 'debian/foo/usr/lib/systemd/user/foo.service'); + ok(! -e 'debian/foo/usr/lib/systemd/user/baz.service'); + is_enabled('foo', 'foo.service'); + isnt_enabled('foo', 'baz.service'); + if ($compat > 13) { + is_started('foo', 'foo.service'); + isnt_started('foo', 'baz.service'); + } else { + isnt_started('foo', 'bar.service'); + isnt_started('foo', 'baz.service'); + } + ok(run_dh_tool('dh_clean')); + + ok(run_dh_tool('dh_installsystemduser', '--name', 'baz')); + ok(! -e 'debian/foo/usr/lib/systemd/user/foo.service'); + ok(-e 'debian/foo/usr/lib/systemd/user/baz.service'); + isnt_enabled('foo', 'foo.service'); + is_enabled('foo', 'baz.service'); + if ($compat > 13) { + isnt_started('foo', 'foo.service'); + is_started('foo', 'baz.service'); + } else { + isnt_started('foo', 'foo.service'); + isnt_started('foo', 'baz.service'); + } + ok(run_dh_tool('dh_clean')); +}; diff --git a/t/dh_link/01-basic.t b/t/dh_link/01-basic.t new file mode 100755 index 0000000..88c8e49 --- /dev/null +++ b/t/dh_link/01-basic.t @@ -0,0 +1,50 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More; +plan(tests => 1); + +use File::Path qw(remove_tree); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; + +each_compat_subtest { + + remove_tree('debian/debhelper'); + + # It used to not make absolute links in this situation, and it should. + # #37774 + ok(run_dh_tool('dh_link', 'etc/foo', 'usr/lib/bar')); + ok(readlink("debian/debhelper/usr/lib/bar"), "/etc/foo"); + + + # let's make sure it makes simple relative links ok. + ok(run_dh_tool('dh_link', 'usr/bin/foo', 'usr/bin/bar')); + ok(readlink("debian/debhelper/usr/bin/bar"), "foo"); + ok(run_dh_tool('dh_link', 'sbin/foo', 'sbin/bar')); + ok(readlink("debian/debhelper/sbin/bar"), "foo"); + + # ok, more complex relative links. + ok(run_dh_tool('dh_link', 'usr/lib/1', 'usr/bin/2')); + ok(readlink("debian/debhelper/usr/bin/2"),"../lib/1"); + + # Check conversion of relative symlink to different top-level directory + # into absolute symlink. (#244157) + system("mkdir -p debian/debhelper/usr/lib; mkdir -p debian/debhelper/lib; touch debian/debhelper/lib/libm.so; cd debian/debhelper/usr/lib; ln -sf ../../lib/libm.so"); + ok(run_dh_tool('dh_link')); + ok(readlink("debian/debhelper/usr/lib/libm.so"), "/lib/libm.so"); + + # Link to self. + ok(run_dh_tool({ 'quiet' => 1 }, 'dh_link', 'usr/lib/foo', 'usr/lib/foo')); + ok(! -l "debian/debhelper/usr/lib/foo"); + + # Make sure the link conversion didn't change any of the + # previously made links. + ok(readlink("debian/debhelper/usr/lib/bar"), "/etc/foo"); + ok(readlink("debian/debhelper/usr/bin/bar"), "foo"); + ok(readlink("debian/debhelper/usr/bin/2"),"../lib/1"); +}; + diff --git a/t/dh_link/02-346405.t b/t/dh_link/02-346405.t new file mode 100755 index 0000000..95053ca --- /dev/null +++ b/t/dh_link/02-346405.t @@ -0,0 +1,29 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More; +plan(tests => 1); + +use File::Path qw(remove_tree); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; + +each_compat_subtest { + + remove_tree('debian/debhelper'); + + # Check links to the current directory and below, they used to be + # unnecessarily long (#346405). + ok(run_dh_tool('dh_link', 'usr/lib/geant4', 'usr/lib/geant4/a')); + ok(readlink("debian/debhelper/usr/lib/geant4/a"), "."); + ok(run_dh_tool('dh_link', 'usr/lib', 'usr/lib/geant4/b')); + ok(readlink("debian/debhelper/usr/lib/geant4/b"), ".."); + ok(run_dh_tool('dh_link', 'usr', 'usr/lib/geant4/c')); + ok(readlink("debian/debhelper/usr/lib/geant4/c"), "../.."); + ok(run_dh_tool('dh_link', '/', 'usr/lib/geant4/d')); + ok(readlink("debian/debhelper/usr/lib/geant4/d"), "/"); +}; + diff --git a/t/dh_link/03-894229.t b/t/dh_link/03-894229.t new file mode 100755 index 0000000..d42a392 --- /dev/null +++ b/t/dh_link/03-894229.t @@ -0,0 +1,55 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More; +plan(tests => 1); + +use File::Path qw(remove_tree); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Debian::Debhelper::Dh_Lib qw(!dirname); +use Test::DH; + + +sub test_tricky { + my ($link_name, $denoted_dest, $expected_link_target) = @_; + my $tmpdir = 'debian/debhelper'; + my $link_path = "${tmpdir}/${link_name}"; + + make_symlink($link_name, $denoted_dest, $tmpdir); + if (ok(-l $link_path, 'Link made in correct directory')) { + my $target = readlink($link_path); + is($target, $expected_link_target, 'Link points correctly') + or diag("Expected ${expected_link_target}, actual ${target}"); + rm_files($link_path); + } + return; +} + +sub test_invalid { + my ($link_name, $denoted_dest) = @_; + eval { + make_symlink($link_name, $denoted_dest); + }; + like($@, qr{^(?:\S*:(?: error:)?\s*)?Invalid destination/link name}); +} + +each_compat_subtest { + + remove_tree('debian/debhelper/a/b/c'); + + mkdirs('debian/debhelper/a/b/c'); + + test_invalid('../../wow', 'a'); + # This is a can be made valid but at the moment we do not support + # it. + test_invalid('a/b/../link21', 'a'); + + + test_tricky('//a/b/link03', 'a/b/c', 'c'); + test_tricky('./a/link18', 'a', '.'); + test_tricky('a/./b/link19', 'a/b', '.'); +}; + diff --git a/t/dh_missing/01-no-missing.t b/t/dh_missing/01-no-missing.t new file mode 100755 index 0000000..e3cd311 --- /dev/null +++ b/t/dh_missing/01-no-missing.t @@ -0,0 +1,28 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; + +our $TEST_DH_FIXTURE_DIR = 'template'; +our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + debian/changelog + debian/control + debian/foo.install + file-for-foo + Makefile +)); + +plan(tests => 1); + +each_compat_subtest { + # Verify dh_missing does not fail when all files are installed. + ok(run_dh_tool('dh_clean')); + is(system('make', 'install'), 0); + ok(run_dh_tool('dh_install', '--sourcedir', 'debian/tmp')); + ok(run_dh_tool('dh_missing', '--fail-missing'), 'dh_missing failed'); +}; + diff --git a/t/dh_missing/02-fail-on-missing.t b/t/dh_missing/02-fail-on-missing.t new file mode 100755 index 0000000..e97b6eb --- /dev/null +++ b/t/dh_missing/02-fail-on-missing.t @@ -0,0 +1,33 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; + +our $TEST_DH_FIXTURE_DIR = 'template'; +our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + debian/changelog + debian/control + debian/foo.install + file-for-foo + Makefile +)); + +plan(tests => 1); + +each_compat_subtest { + # Verify dh_missing does fail when not all files are installed. + ok(run_dh_tool('dh_clean')); + is(system('make', 'installmore'), 0); + ok(run_dh_tool('dh_install', '--sourcedir', 'debian/tmp')); + ok(!run_dh_tool({ 'quiet' => 1 }, 'dh_missing', '--fail-missing')); + + isnt($?, -1, 'dh_missing was executed'); + ok(! ($? & 127), 'dh_missing did not die due to a signal'); + my $exitcode = ($? >> 8); + is($exitcode, 255, 'dh_missing exited with exit code 255'); +}; + diff --git a/t/dh_missing/03-dh_install-redirection.t b/t/dh_missing/03-dh_install-redirection.t new file mode 100755 index 0000000..2235b08 --- /dev/null +++ b/t/dh_missing/03-dh_install-redirection.t @@ -0,0 +1,30 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; + +our $TEST_DH_FIXTURE_DIR = 'template'; +our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + debian/changelog + debian/control + debian/foo.install + file-for-foo + Makefile +)); + +plan(tests => 1); + +each_compat_up_to_and_incl_subtest(10, sub { + # Verify that dh_install -X --fail-missing is passed through to dh_missing (#863447) + # dh_install -Xfile makes file-for-foo not be installed. Then we shouldn't + # complain about it not being missing. + ok(run_dh_tool('dh_clean')); + is(system('make', 'install'), 0); + ok(run_dh_tool({ 'quiet' => 1 }, 'dh_install', '--sourcedir', 'debian/tmp', + '-X', 'more', '--exclude', 'lots', '--fail-missing')); +}); + diff --git a/t/dh_missing/04-not-installed-glob.t b/t/dh_missing/04-not-installed-glob.t new file mode 100755 index 0000000..b46eca3 --- /dev/null +++ b/t/dh_missing/04-not-installed-glob.t @@ -0,0 +1,37 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use Debian::Debhelper::Dh_Lib qw(!dirname); + +our $TEST_DH_FIXTURE_DIR = 'template'; +our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw( + debian/changelog + debian/control + debian/foo.install + file-for-foo + Makefile +)); + +plan(tests => 1); + +each_compat_subtest { + rm_files('debian/not-installed'); + open(my $fd, '>', 'debian/not-installed') or error("open(d/not-installed): $!"); + # Non-glob match + print {$fd} "usr/bin/file-for-foo\n"; + # Glob match (note that it must not match the above) + print {$fd} "usr/bin/file-for-foo-*\n"; + # Non-matches (silently ignored) + print {$fd} "usr/bin/does-not-exist\n"; + print {$fd} "usr/bin/does-not-exist-*\n"; + close($fd) or error("close(d/not-installed: $!"); + ok(run_dh_tool('dh_clean')); + is(system('make', 'installmore'), 0); + ok(run_dh_tool('dh_missing', '--fail-missing')); +}; + diff --git a/t/dh_missing/template/Makefile b/t/dh_missing/template/Makefile new file mode 100644 index 0000000..e33e1df --- /dev/null +++ b/t/dh_missing/template/Makefile @@ -0,0 +1,7 @@ +install: + install -m 755 -d debian/tmp/usr/bin + install -m 644 file-for-foo debian/tmp/usr/bin/file-for-foo + +installmore: install + install -m 644 file-for-foo debian/tmp/usr/bin/file-for-foo-more + install -m 644 file-for-foo debian/tmp/usr/bin/file-for-foo-lots diff --git a/t/dh_missing/template/debian/changelog b/t/dh_missing/template/debian/changelog new file mode 100644 index 0000000..5850f0e --- /dev/null +++ b/t/dh_missing/template/debian/changelog @@ -0,0 +1,5 @@ +foo (1.0-1) unstable; urgency=low + + * Initial release. (Closes: #XXXXXX) + + -- Test <testing@nowhere> Mon, 11 Jul 2016 18:10:59 +0200 diff --git a/t/dh_missing/template/debian/control b/t/dh_missing/template/debian/control new file mode 100644 index 0000000..48d4de2 --- /dev/null +++ b/t/dh_missing/template/debian/control @@ -0,0 +1,20 @@ +Source: foo +Section: misc +Priority: optional +Maintainer: Test <testing@nowhere> +Standards-Version: 3.9.8 + +Package: foo +Architecture: all +Description: package foo + Package foo + +Package: bar +Architecture: all +Description: package bar + Package bar + +Package: baz +Architecture: all +Description: package baz + Package baz diff --git a/t/dh_missing/template/debian/foo.install b/t/dh_missing/template/debian/foo.install new file mode 100644 index 0000000..eddea57 --- /dev/null +++ b/t/dh_missing/template/debian/foo.install @@ -0,0 +1 @@ +usr/bin/*-for-foo
\ No newline at end of file diff --git a/t/dh_missing/template/file-for-foo b/t/dh_missing/template/file-for-foo new file mode 100644 index 0000000..8773f39 --- /dev/null +++ b/t/dh_missing/template/file-for-foo @@ -0,0 +1 @@ +file content
\ No newline at end of file diff --git a/t/dh_usrlocal/01-basic.t b/t/dh_usrlocal/01-basic.t new file mode 100755 index 0000000..9b05516 --- /dev/null +++ b/t/dh_usrlocal/01-basic.t @@ -0,0 +1,157 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More; +plan(tests => 1); + +use File::Path qw(remove_tree); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use Debian::Debhelper::Dh_Lib qw(!dirname); + +sub extract_generated_lines { + my ($file) = @_; + my (@lines, $marker); + return if not -f $file; + open(my $fd, '<', $file) or error("open($file) failed: $!"); + while (my $line = <$fd>) { + chomp($line); + if (defined($marker)) { + last if $line eq $marker; + push(@lines, $line); + next; + } + if ($line =~ m{\s*<<\s*(\S+)\s*$}) { + $marker = $1; + } + } + close($fd); + return @lines; +} + + +sub perform_test { + my ($install_dirs, $expected_dirs_postinst, $expected_dirs_prerm) = @_; + my (@postinst, @prerm); + my @scripts = qw( + debian/debhelper.postinst.debhelper + debian/debhelper.prerm.debhelper + ); + + rm_files(@scripts); + remove_tree('debian/debhelper'); + mkdirs(map { "debian/debhelper/$_" } @{$install_dirs}); + + ok(run_dh_tool('dh_usrlocal')); + + @postinst = extract_generated_lines("debian/debhelper.postinst.debhelper"); + @prerm = extract_generated_lines("debian/debhelper.prerm.debhelper"); + + is_deeply(\@postinst, + [map { "$_ default" } @{$expected_dirs_postinst}], + "Correct postinst" + ) or do { diag("postinst: $_") for @postinst; }; + is_deeply(\@prerm, + $expected_dirs_prerm, + "Correct prerm" + ) or do { diag("prerm: $_") for @prerm; }; +} + +each_compat_subtest { + + perform_test( + ['/usr/local/bar', '/usr/local/foo'], + ['/usr/local/bar', '/usr/local/foo'], + [] + ); + + perform_test( + [ + '/usr/local/foo/bar', + '/usr/local/foo/baz', + ], + [ + '/usr/local/foo', + '/usr/local/foo/bar', + '/usr/local/foo/baz', + ], + [ + '/usr/local/foo/bar', + '/usr/local/foo/baz', + ] + ); + + perform_test( + [qw( + /usr/local/a/a/a + /usr/local/a/a/b + /usr/local/a/b/a + /usr/local/a/b/b + /usr/local/b/a/a + /usr/local/b/a/b + /usr/local/b/b/a + /usr/local/b/b/b + )], + [qw( + /usr/local/a + /usr/local/a/a + /usr/local/a/a/a + /usr/local/a/a/b + /usr/local/a/b + /usr/local/a/b/a + /usr/local/a/b/b + /usr/local/b + /usr/local/b/a + /usr/local/b/a/a + /usr/local/b/a/b + /usr/local/b/b + /usr/local/b/b/a + /usr/local/b/b/b + )], + [qw( + /usr/local/a/a/a + /usr/local/a/a/b + /usr/local/a/a + /usr/local/a/b/a + /usr/local/a/b/b + /usr/local/a/b + /usr/local/b/a/a + /usr/local/b/a/b + /usr/local/b/a + /usr/local/b/b/a + /usr/local/b/b/b + /usr/local/b/b + )] + ); + + perform_test( + [ + '/usr/local/foo/dir/somewhere', + '/usr/local/bar/another-dir/elsewhere', + '/usr/local/baz/foo+bar/thing', + ], + [ + '/usr/local/bar', + '/usr/local/bar/another-dir', + '/usr/local/bar/another-dir/elsewhere', + '/usr/local/baz', + '/usr/local/baz/foo+bar', + '/usr/local/baz/foo+bar/thing', + '/usr/local/foo', + '/usr/local/foo/dir', + '/usr/local/foo/dir/somewhere', + ], + [ + '/usr/local/bar/another-dir/elsewhere', + '/usr/local/bar/another-dir', + '/usr/local/baz/foo+bar/thing', + '/usr/local/baz/foo+bar', + '/usr/local/foo/dir/somewhere', + '/usr/local/foo/dir', + ] + ); +}; + diff --git a/t/maintscript.t b/t/maintscript.t new file mode 100755 index 0000000..cec4fab --- /dev/null +++ b/t/maintscript.t @@ -0,0 +1,70 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; + +use File::Path qw(remove_tree); +use File::Basename qw(dirname); +use lib dirname(__FILE__); +use Test::DH; +use Debian::Debhelper::Dh_Lib qw(!dirname); + +plan(tests => 2); + +each_compat_up_to_and_incl_subtest(10, sub { + my @scripts = qw{postinst preinst prerm postrm}; + my $file = 'debian/maintscript'; + + remove_tree('debian/debhelper', 'debian/tmp'); + rm_files(@scripts, $file); + + open(my $fd, ">", $file) || die("open($file): $!"); + print {$fd} <<EOF; +rm_conffile /etc/1 +mv_conffile /etc/2 /etc/3 1.0-1 +EOF + close($fd) or die("close($file): $!\n"); + + run_dh_tool('dh_installdeb'); + + for my $script (@scripts) { + my @output=`cat debian/debhelper.$script.debhelper`; + ok(grep { m{^dpkg-maintscript-helper rm_conffile /etc/1 -- "\$\@"$} } @output); + ok(grep { m{^dpkg-maintscript-helper mv_conffile /etc/2 /etc/3 1\.0-1 -- "\$\@"$} } @output); + } +}); + +sub test_maintscript_syntax { + my ($contents) = @_; + my @scripts = map { ("debian/debhelper.${_}.debhelper", "debian/$_") } qw{postinst preinst prerm postrm}; + my $file = 'debian/maintscript'; + + + open(my $fd, ">", $file) or die("open($file): $!"); + print {$fd} <<EOF; +${contents} +EOF + close($fd) or die("close($file): $!\n"); + + my $res = run_dh_tool( { 'quiet' => 1 }, 'dh_installdeb'); + + remove_tree('debian/debhelper', 'debian/tmp', 'debian/.debhelper'); + rm_files(@scripts); + + return $res; +} + +# Negative tests +each_compat_from_and_above_subtest(12, sub { + ok(!test_maintscript_syntax('rm_conffile foo 1.0~'), "rm_conffile absolute path check"); + ok(!test_maintscript_syntax('rm_conffile /foo 1.0\~'), "rm_conffile version check"); + ok(!test_maintscript_syntax('rm_conffile /foo 1.0~ some_pkg'), "rm_conffile package name check"); + ok(!test_maintscript_syntax('rm_conffile /foo 1.0~ some-pkg --'), "rm_conffile separator check"); + + ok(!test_maintscript_syntax('mv_conffile foo /bar 1.0~'), "mv_conffile absolute (current) path check"); + ok(!test_maintscript_syntax('mv_conffile /foo bar 1.0~'), "mv_conffile absolute (current) path check"); + ok(!test_maintscript_syntax('mv_conffile /foo /bar 1.0\~'), "mv_conffile version check"); + ok(!test_maintscript_syntax('mv_conffile /foo /bar 1.0~ some_pkg'), "mv_conffile package name check"); + ok(!test_maintscript_syntax('mv_conffile /foo /bar 1.0~ some-pkg -- '), "mv_conffile separator check "); +}); + diff --git a/t/override_target.t b/t/override_target.t new file mode 100755 index 0000000..235f904 --- /dev/null +++ b/t/override_target.t @@ -0,0 +1,30 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; +plan(tests => 1); + +# This test is here to detect breakage in +# dh's rules_explicit_target, which parses +# slightly internal make output. +system("mkdir -p t/tmp/debian"); +system("cp debian/control debian/compat debian/changelog t/tmp/debian"); +open (OUT, ">", "t/tmp/debian/rules") || die "$!"; +my $binpath = $ENV{AUTOPKGTEST_TMP} ? '/usr/bin' : '../..'; +print OUT <<EOF; +#!/usr/bin/make -f +%: + PATH=../..:\$\$PATH PERL5LIB=../../lib $binpath/dh \$@ --without autoreconf + +override_dh_update_autotools_config override_dh_strip_nondeterminism: + +override_dh_auto_build: + echo "override called" +EOF +close OUT; +system("chmod +x t/tmp/debian/rules"); +my @output=`cd t/tmp && debian/rules build 2>&1`; +ok(grep { m/override called/ } @output) or do { + diag($_) for @output; +}; +system("rm -rf t/tmp"); @@ -0,0 +1,10 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More; + +eval { require Test::Pod; Test::Pod->import; }; +plan skip_all => 'Test::Pod required' if $@; + +all_pod_files_ok('debhelper.pod', grep { -x $_ } 'dh', glob 'dh_*'); diff --git a/t/size.t b/t/size.t new file mode 100755 index 0000000..e759a47 --- /dev/null +++ b/t/size.t @@ -0,0 +1,32 @@ +#!/usr/bin/perl +# This may appear arbitrary, but DO NOT CHANGE IT. +# Debhelper is supposed to consist of small, simple, easy to understand +# programs. Programs growing in size and complexity without bounds is a +# bug. +use strict; +use warnings; +use Test::More; + +my $binpath = $ENV{AUTOPKGTEST_TMP} ? '/usr/bin' : '.'; +my @progs=grep { -x $_ } glob("$binpath/dh_*"); + +plan(tests => (@progs + @progs)); + +foreach my $file (@progs) { + + my $lines=0; + my $maxlength=0; + open(my $fd, '<', $file) || die "open($file): $!"; + my $cutting=0; + while (<$fd>) { + $cutting=1 if /^=/; + $cutting=0 if /^=cut/; + next if $cutting || /^(?:=|\s*(?:\#.*|[}]\s*)?$)/; + $lines++; + $maxlength=length($_) if length($_) > $maxlength; + } + close($fd); + print "# $file has $lines lines, max length is $maxlength\n"; + ok($lines < 200, $file); + ok($maxlength < 160, $file); +} diff --git a/t/syntax/syntax-libs.t b/t/syntax/syntax-libs.t new file mode 120000 index 0000000..fedf32e --- /dev/null +++ b/t/syntax/syntax-libs.t @@ -0,0 +1 @@ +syntax-progs.t
\ No newline at end of file diff --git a/t/syntax/syntax-progs.t b/t/syntax/syntax-progs.t new file mode 100755 index 0000000..93d00bb --- /dev/null +++ b/t/syntax/syntax-progs.t @@ -0,0 +1,28 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +# Need Test::More to set PERL5LIB +use Test::DH; + +use Config; +my $binpath = $ENV{AUTOPKGTEST_TMP} ? '/usr/bin' : '.'; +my $libpath = $ENV{AUTOPKGTEST_TMP} ? $Config{vendorlib} : 'lib'; + +my @targets; +if ($0 =~ m{syntax-progs\.t$}) { + @targets = grep { -x $_ } glob("$binpath/dh_*"), "$binpath/dh"; +} else { + @targets = (glob("$libpath/Debian/Debhelper/*.pm"), glob("$libpath/Debian/Debhelper/*/*.pm")); +} + +plan(tests => scalar(@targets)); + +foreach my $file (@targets) { + is(system("perl -c $file >/dev/null 2>&1"), 0) + or diag("$file failed syntax check"); +} + |