From 5064d392c378b94849969b319ca137a0d81b7fa1 Mon Sep 17 00:00:00 2001 From: Alexander Karelas Date: Mon, 26 Aug 2024 13:52:05 +0000 Subject: [PATCH 1/3] Test diff_package_list on real-world Redhat data --- t/package.t | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/t/package.t b/t/package.t index ea6efae2a..d62122b2f 100755 --- a/t/package.t +++ b/t/package.t @@ -5,12 +5,15 @@ use warnings; our $VERSION = '9999.99.99_99'; # VERSION -use Test::More tests => 3; +use Test::More tests => 4; use Test::Warnings; use Test::Deep; use Test::Exception; use Rex::Pkg::Test; +use Rex::Pkg::Redhat; + +use Storable 'dclone'; my $pkg = Rex::Pkg::Test->new; @@ -62,4 +65,75 @@ subtest 'local package installation' => sub { lives_ok { $pkg->update('test_package') }, 'update test package'; }; +subtest 'redhat package list diffs' => sub { + ## no critic (ProhibitDuplicateLiteral) + + plan tests => 4; + + my $rh_pkg = Rex::Pkg::Redhat->new; + + my @orig = ( + { + 'arch' => 'x86_64', + 'version' => '5.14.0', + 'release' => '427.26.1.el9_4', + 'name' => 'kernel', + 'epoch' => '0', + }, + { + 'version' => '5.14.0', + 'arch' => 'x86_64', + 'name' => 'kernel', + 'epoch' => '0', + 'release' => '427.28.1.el9_4', + }, + { + 'arch' => 'x86_64', + 'version' => '5.14.0', + 'name' => 'kernel', + 'epoch' => '0', + 'release' => '427.31.1.el9_4', + }, + ); + + my @plist1 = @{ dclone( \@orig ) }; + my @plist2 = @{ dclone( \@orig ) }; + my @expected = (); + + my @mods = $rh_pkg->diff_package_list( \@plist1, \@plist2 ); + cmp_deeply( \@mods, \@expected, + 'expected package modifications when nothing changed' ); + + @plist1 = @{ dclone( \@orig ) }; + pop @plist1; + @plist2 = @{ dclone( \@orig ) }; + @expected = ( { %{ $orig[2] }, action => 'installed' } ); + + @mods = $rh_pkg->diff_package_list( \@plist1, \@plist2 ); + cmp_deeply( \@mods, \@expected, + 'expected package modifications when new kernel release is installed' ); + + @plist1 = @{ dclone( \@orig ) }; + pop @plist1; + @plist2 = @{ dclone( \@orig ) }; + shift @plist2; + @expected = ( { %{ $orig[2] }, action => 'updated' } ); + + @mods = $rh_pkg->diff_package_list( \@plist1, \@plist2 ); + cmp_deeply( \@mods, \@expected, + 'expected package modifications when new kernel release is installed and an old one removed' + ); + + @plist1 = @{ dclone( \@orig ) }; + @plist2 = @{ dclone( \@orig ) }; + shift @plist2; + @expected = ( { %{ $orig[0] }, action => 'removed' } ); + + @mods = $rh_pkg->diff_package_list( \@plist1, \@plist2 ); + cmp_deeply( \@mods, \@expected, + 'expected package modifications when only a kernel release is removed' ); + + ## use critic +}; + 1; From 7dc97a2dc0b7c00cf3e8878b9263c2336665fd2e Mon Sep 17 00:00:00 2001 From: Alexander Karelas Date: Mon, 26 Aug 2024 13:59:53 +0000 Subject: [PATCH 2/3] Fix update_system's on_change on Redhat Redhat can have multiple packages installed with the same name (eg kernels), a fact that Rex::Pkg::Base::diff_package_list is not prepared to deal with, resulting in calling the on_change hook when you run the update_system command, even if nothing changed in the packages installed (see also bug #1149). This commit fixes that. --- ChangeLog | 1 + lib/Rex/Pkg/Redhat.pm | 53 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/ChangeLog b/ChangeLog index df4b0805f..7bacb0b12 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,7 @@ Revision history for Rex - Return only the first found command - Fix inconsistent augtool wrapper usage - Fix Config::Augeas detection + - Fix on_change in update_system command on Redhat [DOCUMENTATION] diff --git a/lib/Rex/Pkg/Redhat.pm b/lib/Rex/Pkg/Redhat.pm index 506f6f3b9..c74ee1e93 100644 --- a/lib/Rex/Pkg/Redhat.pm +++ b/lib/Rex/Pkg/Redhat.pm @@ -84,6 +84,59 @@ sub get_installed { return @pkg; } +sub diff_package_list { + my ( $self, $list1, $list2 ) = @_; + + my @old_installed = @{$list1}; + my @new_installed = @{$list2}; + + my @modifications; + + my %old_installed; + foreach my $old_pkg (@old_installed) { + my $name = $old_pkg->{name}; + my $version = "$old_pkg->{version} $old_pkg->{release}"; + $old_installed{$name}{$version} = $old_pkg; + } + + my %new_installed; + foreach my $new_pkg (@new_installed) { + my $name = $new_pkg->{name}; + my $version = "$new_pkg->{version} $new_pkg->{release}"; + if ( $old_installed{$name} and $old_installed{$name}{$version} ) { + delete $old_installed{$name}{$version}; + if ( !keys %{ $old_installed{$name} } ) { + delete $old_installed{$name}; + } + next; + } + $new_installed{$name}{$version} = $new_pkg; + } + + foreach my $new_name ( keys %new_installed ) { + if ( $old_installed{$new_name} ) { + foreach my $pkg ( values %{ $new_installed{$new_name} } ) { + push @modifications, { %{$pkg}, action => 'updated' }; + } + } + else { + foreach my $pkg ( values %{ $new_installed{$new_name} } ) { + push @modifications, { %{$pkg}, action => 'installed' }; + } + } + } + + foreach my $old_name ( keys %old_installed ) { + if ( !$new_installed{$old_name} ) { + foreach my $pkg ( values %{ $old_installed{$old_name} } ) { + push @modifications, { %{$pkg}, action => 'removed' }; + } + } + } + + return @modifications; +} + sub add_repository { my ( $self, %data ) = @_; From c90e9df3f34340a67a0a95133e61c46b88bfbc80 Mon Sep 17 00:00:00 2001 From: Ferenc Erki Date: Sat, 31 Aug 2024 20:32:55 +0200 Subject: [PATCH 3/3] Refine Red Hat package modification tests --- t/package.t | 125 +++++++++++++++++++++++++++++----------------------- 1 file changed, 71 insertions(+), 54 deletions(-) diff --git a/t/package.t b/t/package.t index d62122b2f..5c81888e9 100755 --- a/t/package.t +++ b/t/package.t @@ -13,8 +13,6 @@ use Test::Exception; use Rex::Pkg::Test; use Rex::Pkg::Redhat; -use Storable 'dclone'; - my $pkg = Rex::Pkg::Test->new; subtest 'package list diffs' => sub { @@ -66,74 +64,93 @@ subtest 'local package installation' => sub { }; subtest 'redhat package list diffs' => sub { - ## no critic (ProhibitDuplicateLiteral) - - plan tests => 4; + plan tests => 1; my $rh_pkg = Rex::Pkg::Redhat->new; - my @orig = ( + ## no critic (ProhibitDuplicateLiteral) + + my @before = ( { - 'arch' => 'x86_64', - 'version' => '5.14.0', - 'release' => '427.26.1.el9_4', - 'name' => 'kernel', - 'epoch' => '0', + arch => 'x86_64', + epoch => '0', + name => 'lzo', + release => '8.el7', + version => '2.06', }, { - 'version' => '5.14.0', - 'arch' => 'x86_64', - 'name' => 'kernel', - 'epoch' => '0', - 'release' => '427.28.1.el9_4', + arch => 'x86_64', + epoch => '0', + name => 'postgresql-server', + release => '1.el7', + version => '9.2.18', }, { - 'arch' => 'x86_64', - 'version' => '5.14.0', - 'name' => 'kernel', - 'epoch' => '0', - 'release' => '427.31.1.el9_4', + arch => 'x86_64', + epoch => '0', + name => 'kernel', + release => '427.26.1.el9_4', + version => '5.14.0', }, ); - my @plist1 = @{ dclone( \@orig ) }; - my @plist2 = @{ dclone( \@orig ) }; - my @expected = (); - - my @mods = $rh_pkg->diff_package_list( \@plist1, \@plist2 ); - cmp_deeply( \@mods, \@expected, - 'expected package modifications when nothing changed' ); - - @plist1 = @{ dclone( \@orig ) }; - pop @plist1; - @plist2 = @{ dclone( \@orig ) }; - @expected = ( { %{ $orig[2] }, action => 'installed' } ); - - @mods = $rh_pkg->diff_package_list( \@plist1, \@plist2 ); - cmp_deeply( \@mods, \@expected, - 'expected package modifications when new kernel release is installed' ); - - @plist1 = @{ dclone( \@orig ) }; - pop @plist1; - @plist2 = @{ dclone( \@orig ) }; - shift @plist2; - @expected = ( { %{ $orig[2] }, action => 'updated' } ); + my @after = ( + { + arch => 'x86_64', + epoch => '0', + name => 'postgresql-server', + release => '1.el7', + version => '9.2.19', + }, + { + arch => 'x86_64', + epoch => '0', + name => 'kernel', + release => '427.28.1.el9_4', + version => '5.14.0', + }, + { + arch => 'x86_64', + epoch => '0', + name => 'kernel', + release => '427.26.1.el9_4', + version => '5.14.0', + }, + ); - @mods = $rh_pkg->diff_package_list( \@plist1, \@plist2 ); - cmp_deeply( \@mods, \@expected, - 'expected package modifications when new kernel release is installed and an old one removed' + my @expected = ( + { + action => 'updated', + arch => 'x86_64', + epoch => '0', + name => 'postgresql-server', + release => '1.el7', + version => '9.2.19', + }, + { + action => 'installed', + arch => 'x86_64', + epoch => '0', + name => 'kernel', + release => '427.28.1.el9_4', + version => '5.14.0', + }, + { + action => 'removed', + arch => 'x86_64', + epoch => '0', + name => 'lzo', + release => '8.el7', + version => '2.06', + }, ); - @plist1 = @{ dclone( \@orig ) }; - @plist2 = @{ dclone( \@orig ) }; - shift @plist2; - @expected = ( { %{ $orig[0] }, action => 'removed' } ); + ## use critic - @mods = $rh_pkg->diff_package_list( \@plist1, \@plist2 ); - cmp_deeply( \@mods, \@expected, - 'expected package modifications when only a kernel release is removed' ); + my @mods = $rh_pkg->diff_package_list( \@before, \@after ); - ## use critic + cmp_bag( \@mods, \@expected, + 'expected package modifications on Red Hat compatible distros' ); }; 1;