diff --git a/t/001-deb-systemd-helper.t b/t/001-deb-systemd-helper.t index ed661c8..01e2984 100644 --- a/t/001-deb-systemd-helper.t +++ b/t/001-deb-systemd-helper.t @@ -18,17 +18,20 @@ use Linux::Clone; # neither in core nor in Debian :-/ my $dsh = "$FindBin::Bin/../script/deb-systemd-helper"; -sub _unit_enabled { - my ($unit_file, $cb, $verb) = @_; +sub _unit_check { + my ($unit_file, $cmd, $cb, $verb) = @_; - my $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh is-enabled $unit_file"); + my $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh $cmd $unit_file"); isnt($retval, -1, 'deb-systemd-helper could be executed'); ok(!($retval & 127), 'deb-systemd-helper did not exit due to a signal'); - $cb->($retval >> 8, 0, "random unit file $verb enabled"); + $cb->($retval >> 8, 0, "random unit file $verb $cmd"); } -sub is_enabled { _unit_enabled($_[0], \&is, 'is') } -sub isnt_enabled { _unit_enabled($_[0], \&isnt, 'isnt') } +sub is_enabled { _unit_check($_[0], 'is-enabled', \&is, 'is') } +sub isnt_enabled { _unit_check($_[0], 'is-enabled', \&isnt, 'isnt') } + +sub is_debian_installed { _unit_check($_[0], 'debian-installed', \&is, 'is') } +sub isnt_debian_installed { _unit_check($_[0], 'debian-installed', \&isnt, 'isnt') } my $retval = Linux::Clone::unshare Linux::Clone::NEWNS; BAIL_OUT("Cannot unshare(NEWNS): $!") if $retval != 0; @@ -57,6 +60,7 @@ close($fh); $random_unit = basename($random_unit); isnt_enabled($random_unit); +isnt_debian_installed($random_unit); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “is-enabled” is not true for a random, existing unit file. ┃ @@ -78,6 +82,7 @@ EOT close($fh); isnt_enabled($random_unit); +isnt_debian_installed($random_unit); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “enable” creates the requested symlinks. ┃ @@ -97,6 +102,7 @@ is(readlink($symlink_path), $servicefile_path, # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ is_enabled($random_unit); +is_debian_installed($random_unit); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify deleting the symlinks and running “enable” again does not ┃ @@ -106,6 +112,7 @@ is_enabled($random_unit); unlink($symlink_path); ok(! -l $symlink_path, 'symlink deleted'); isnt_enabled($random_unit); +is_debian_installed($random_unit); $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable $random_unit"); @@ -122,6 +129,7 @@ ok(-f $statefile, 'state file exists'); $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test _DEB_SYSTEMD_HELPER_PURGE=1 $dsh disable $random_unit"); ok(! -f $statefile, 'state file does not exist anymore after purging'); +isnt_debian_installed($random_unit); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “enable” after purging does re-create the symlinks. ┃ @@ -133,5 +141,6 @@ isnt_enabled($random_unit); $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable $random_unit"); is_enabled($random_unit); +is_debian_installed($random_unit); done_testing; diff --git a/t/002-deb-systemd-helper-update.t b/t/002-deb-systemd-helper-update.t index 97621d2..ae401e9 100644 --- a/t/002-deb-systemd-helper-update.t +++ b/t/002-deb-systemd-helper-update.t @@ -105,7 +105,7 @@ is_enabled($random_unit); # ┃ Modify the unit file and verify that “is-enabled” is no longer true. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ -open($fh, '>', $servicefile_path); +open($fh, '>>', $servicefile_path); print $fh "Alias=newalias.service\n"; close($fh); @@ -152,4 +152,86 @@ is_deeply( [ $symlink_path, $new_symlink_path ], 'state file updated'); +# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +# ┃ Modify the unit file and verify that “is-enabled” is no longer true. ┃ +# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +open($fh, '>>', $servicefile_path); +print $fh "Alias=another.service\n"; +close($fh); + +isnt_enabled($random_unit); + +# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +# ┃ Verify “was-enabled” is still true (operates on the state file). ┃ +# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +$retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh was-enabled $random_unit"); +isnt($retval, -1, 'deb-systemd-helper could be executed'); +ok(!($retval & 127), 'deb-systemd-helper did not exit due to a signal'); +is($retval >> 8, 0, "random unit file was-enabled"); + +# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +# ┃ Verify the new symlink is not yet in the state file. ┃ +# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +is_deeply( + [ state_file_entries($statefile) ], + [ $symlink_path, $new_symlink_path ], + 'state file does not contain the new link yet'); + +# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +# ┃ Verify “update-state” does not create the symlink, but records it in the ┃ +# ┃ state file. ┃ +# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +my $new_symlink_path2 = '/etc/systemd/system/another.service'; +ok(! -l $new_symlink_path2, 'new symlink does not exist yet'); + +$retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh update-state $random_unit"); +ok(! -l $new_symlink_path2, 'new symlink still does not exist'); + +isnt_enabled($random_unit); + +is_deeply( + [ state_file_entries($statefile) ], + [ $symlink_path, $new_symlink_path, $new_symlink_path2 ], + 'state file updated'); + +# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +# ┃ Rewrite the original contents and verify “update-state” removes the old ┃ +# ┃ links that are no longer present. ┃ +# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +open($fh, '>', $servicefile_path); +print $fh <<'EOT'; +[Unit] +Description=test unit + +[Service] +ExecStart=/bin/sleep 1 + +[Install] +WantedBy=multi-user.target +EOT +close($fh); + +unlink($new_symlink_path); + +ok(! -l $new_symlink_path, 'new symlink still does not exist'); +ok(! -l $new_symlink_path2, 'new symlink 2 still does not exist'); + +$retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh update-state $random_unit"); + +ok(! -l $new_symlink_path, 'new symlink still does not exist'); +ok(! -l $new_symlink_path2, 'new symlink 2 still does not exist'); + +is_enabled($random_unit); + +is_deeply( + [ state_file_entries($statefile) ], + [ $symlink_path ], + 'state file updated'); + + done_testing; diff --git a/t/003-deb-systemd-helper-complex.t b/t/003-deb-systemd-helper-complex.t new file mode 100644 index 0000000..924013a --- /dev/null +++ b/t/003-deb-systemd-helper-complex.t @@ -0,0 +1,142 @@ +#!perl +# vim:ts=4:sw=4:et + +use strict; +use warnings; +use Test::More; +use File::Temp qw(tempfile tempdir); # in core since perl 5.6.1 +use File::Path qw(make_path); # in core since Perl 5.001 +use File::Basename; # in core since Perl 5 +use FindBin; # in core since Perl 5.00307 +use Linux::Clone; # neither in core nor in Debian :-/ + +# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +# ┃ SETUP: in a new mount namespace, bindmount tmpdirs on /etc/systemd and ┃ +# ┃ /var/lib/systemd to start with clean directories yet use the actual ┃ +# ┃ locations and code paths. ┃ +# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +my $dsh = "$FindBin::Bin/../script/deb-systemd-helper"; + +sub _unit_check { + my ($unit_file, $cmd, $cb, $verb) = @_; + + my $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh $cmd $unit_file"); + isnt($retval, -1, 'deb-systemd-helper could be executed'); + ok(!($retval & 127), 'deb-systemd-helper did not exit due to a signal'); + $cb->($retval >> 8, 0, "random unit file $unit_file $verb $cmd"); +} + +sub is_enabled { _unit_check($_[0], 'is-enabled', \&is, 'is') } +sub isnt_enabled { _unit_check($_[0], 'is-enabled', \&isnt, 'isnt') } + +sub is_debian_installed { _unit_check($_[0], 'debian-installed', \&is, 'is') } +sub isnt_debian_installed { _unit_check($_[0], 'debian-installed', \&isnt, 'isnt') } + +my $retval = Linux::Clone::unshare Linux::Clone::NEWNS; +BAIL_OUT("Cannot unshare(NEWNS): $!") if $retval != 0; + +sub bind_mount_tmp { + my ($dir) = @_; + my $tmp = tempdir(CLEANUP => 1); + system("mount -n --bind $tmp $dir") == 0 + or BAIL_OUT("bind-mounting $tmp to $dir failed: $!"); + return $tmp; +} + +my $etc_systemd = bind_mount_tmp('/etc/systemd'); +my $lib_systemd = bind_mount_tmp('/lib/systemd'); +my $var_lib_systemd = bind_mount_tmp('/var/lib/systemd'); + +# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +# ┃ Create two unit files with random names; one refers to the other (Also=). ┃ +# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +my ($fh1, $random_unit1) = tempfile('unitXXXXX', + SUFFIX => '.service', + TMPDIR => 1, + UNLINK => 1); +close($fh1); +$random_unit1 = basename($random_unit1); + +my ($fh2, $random_unit2) = tempfile('unitXXXXX', + SUFFIX => '.service', + TMPDIR => 1, + UNLINK => 1); +close($fh2); +$random_unit2 = basename($random_unit2); + +my $servicefile_path1 = "/lib/systemd/system/$random_unit1"; +my $servicefile_path2 = "/lib/systemd/system/$random_unit2"; +make_path('/lib/systemd/system'); +open($fh1, '>', $servicefile_path1); +print $fh1 <', $servicefile_path2); +print $fh2 <; +is_deeply( + \%links, + { + $random_unit1 => $servicefile_path1, + $random_unit2 => $servicefile_path2, + }, + 'All expected links present'); + +my $alias_path = '/etc/systemd/system/alias2.service'; +ok(-l $alias_path, 'alias created'); +is(readlink($alias_path), $servicefile_path2, + 'alias points to the correct service file'); + +# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +# ┃ Verify “is-enabled” now returns true. ┃ +# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +is_enabled($random_unit1); +is_enabled($random_unit2); +is_debian_installed($random_unit1); + +# $random_unit2 was only enabled _because of_ $random_unit1’s Also= statement +# and thus does not have its own state file. +isnt_debian_installed($random_unit2); + +# TODO: cleanup tests? + +done_testing;