From 797ec6900a2b069be199977ed37ab7fdfd9ee298 Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Tue, 27 Jan 2026 07:58:36 +0000 Subject: [PATCH] Bug 41651: (follow-up) Add test coverage for dependency checking Tests for _check_dependencies(): - No dependency files present (passes silently) - cpanfile with satisfied dependencies (passes) - cpanfile with unmet dependencies (dies with message) - META.json with satisfied dependencies (passes) - META.yml with satisfied dependencies (passes) - META.json with unmet dependencies (dies) - Multiple unmet dependencies are all reported Tests for InstallPlugins() with 'from' parameter: - Files are copied from staging to plugins directory - cpanfile is NOT copied to plugins directory - META.json is NOT copied to plugins directory - META.yml is NOT copied to plugins directory - Trailing slash in path is handled correctly --- t/db_dependent/Koha/Plugins/Plugins.t | 238 ++++++++++++++++++++++++-- 1 file changed, 227 insertions(+), 11 deletions(-) diff --git a/t/db_dependent/Koha/Plugins/Plugins.t b/t/db_dependent/Koha/Plugins/Plugins.t index ad368594bfd..594e7177cc1 100755 --- a/t/db_dependent/Koha/Plugins/Plugins.t +++ b/t/db_dependent/Koha/Plugins/Plugins.t @@ -26,7 +26,7 @@ use List::MoreUtils qw(none); use Module::Load::Conditional qw(can_load); use Test::MockModule; use Test::NoWarnings; -use Test::More tests => 20; +use Test::More tests => 22; use Test::Warn; use Test::Exception; @@ -563,20 +563,20 @@ subtest 'Test _version_compare' => sub { t::lib::Mocks::mock_config( 'enable_plugins', 1 ); is( Koha::Plugins::Base::_version_compare( '1.1.1', '2.2.2' ), -1, "1.1.1 is less then 2.2.2" ); - is( Koha::Plugins::Base::_version_compare( '2.2.2', '1.1.1' ), 1, "1.1.1 is greater then 2.2.2" ); - is( Koha::Plugins::Base::_version_compare( '1.1.1', '1.1.1' ), 0, "1.1.1 is equal to 1.1.1" ); - is( Koha::Plugins::Base::_version_compare( '1.01.001', '1.1.1' ), 0, "1.01.001 is equal to 1.1.1" ); - is( Koha::Plugins::Base::_version_compare( '1', '1.0.0' ), 0, "1 is equal to 1.0.0" ); - is( Koha::Plugins::Base::_version_compare( '1.0', '1.0.0' ), 0, "1.0 is equal to 1.0.0" ); + is( Koha::Plugins::Base::_version_compare( '2.2.2', '1.1.1' ), 1, "1.1.1 is greater then 2.2.2" ); + is( Koha::Plugins::Base::_version_compare( '1.1.1', '1.1.1' ), 0, "1.1.1 is equal to 1.1.1" ); + is( Koha::Plugins::Base::_version_compare( '1.01.001', '1.1.1' ), 0, "1.01.001 is equal to 1.1.1" ); + is( Koha::Plugins::Base::_version_compare( '1', '1.0.0' ), 0, "1 is equal to 1.0.0" ); + is( Koha::Plugins::Base::_version_compare( '1.0', '1.0.0' ), 0, "1.0 is equal to 1.0.0" ); # OO tests my $plugin = Koha::Plugin::Test->new; is( $plugin->_version_compare( '1.1.1', '2.2.2' ), -1, "1.1.1 is less then 2.2.2" ); - is( $plugin->_version_compare( '2.2.2', '1.1.1' ), 1, "1.1.1 is greater then 2.2.2" ); - is( $plugin->_version_compare( '1.1.1', '1.1.1' ), 0, "1.1.1 is equal to 1.1.1" ); - is( $plugin->_version_compare( '1.01.001', '1.1.1' ), 0, "1.01.001 is equal to 1.1.1" ); - is( $plugin->_version_compare( '1', '1.0.0' ), 0, "1 is equal to 1.0.0" ); - is( $plugin->_version_compare( '1.0', '1.0.0' ), 0, "1.0 is equal to 1.0.0" ); + is( $plugin->_version_compare( '2.2.2', '1.1.1' ), 1, "1.1.1 is greater then 2.2.2" ); + is( $plugin->_version_compare( '1.1.1', '1.1.1' ), 0, "1.1.1 is equal to 1.1.1" ); + is( $plugin->_version_compare( '1.01.001', '1.1.1' ), 0, "1.01.001 is equal to 1.1.1" ); + is( $plugin->_version_compare( '1', '1.0.0' ), 0, "1 is equal to 1.0.0" ); + is( $plugin->_version_compare( '1.0', '1.0.0' ), 0, "1.0 is equal to 1.0.0" ); }; subtest 'bundle_path() tests' => sub { @@ -619,6 +619,222 @@ subtest 'new() tests' => sub { is( ref($result), 'Koha::Plugins', 'calling new with enable_plugins makes it override the config' ); }; +subtest '_check_dependencies() tests' => sub { + + plan tests => 7; + + t::lib::Mocks::mock_config( 'enable_plugins', 1 ); + + my $plugins = Koha::Plugins->new( { enable_plugins => 1 } ); + + # Test with no dependency files - should pass silently + my $empty_dir = tempdir( CLEANUP => 1 ); + lives_ok { $plugins->_check_dependencies($empty_dir) } + 'No dependency files - passes without error'; + + # Test with cpanfile that has satisfied dependencies + my $cpanfile_ok_dir = tempdir( CLEANUP => 1 ); + open my $fh, '>', "$cpanfile_ok_dir/cpanfile" or die "Cannot create cpanfile: $!"; + print $fh "requires 'Modern::Perl';\n"; # This should be installed + close $fh; + lives_ok { $plugins->_check_dependencies($cpanfile_ok_dir) } + 'cpanfile with satisfied dependencies - passes'; + + # Test with cpanfile that has unsatisfied dependencies + my $cpanfile_bad_dir = tempdir( CLEANUP => 1 ); + open $fh, '>', "$cpanfile_bad_dir/cpanfile" or die "Cannot create cpanfile: $!"; + print $fh "requires 'Some::Nonexistent::Module::XYZ123';\n"; + close $fh; + throws_ok { $plugins->_check_dependencies($cpanfile_bad_dir) } + qr/Unmet dependencies:/, + 'cpanfile with unmet dependencies - dies with message'; + + # Test with META.json that has satisfied dependencies (CPAN::Meta 2.0 format) + my $meta_json_dir = tempdir( CLEANUP => 1 ); + open $fh, '>', "$meta_json_dir/META.json" or die "Cannot create META.json: $!"; + print $fh <<'JSON'; +{ + "abstract": "Test plugin", + "author": ["Test "], + "dynamic_config": 0, + "generated_by": "Test", + "license": ["gpl_3"], + "meta-spec": { "version": 2 }, + "name": "Test-Plugin", + "release_status": "stable", + "version": "1.0", + "prereqs": { + "runtime": { + "requires": { + "Modern::Perl": "0" + } + } + } +} +JSON + close $fh; + lives_ok { $plugins->_check_dependencies($meta_json_dir) } + 'META.json with satisfied dependencies - passes'; + + # Test with META.yml that has satisfied dependencies (CPAN::Meta 1.4 format) + my $meta_yml_dir = tempdir( CLEANUP => 1 ); + open $fh, '>', "$meta_yml_dir/META.yml" or die "Cannot create META.yml: $!"; + print $fh <<'YAML'; +meta-spec: + version: 1.4 +name: Test-Plugin +version: 1.0 +abstract: Test plugin +author: + - Test +license: perl +requires: + Modern::Perl: 0 +YAML + close $fh; + lives_ok { $plugins->_check_dependencies($meta_yml_dir) } + 'META.yml with satisfied dependencies - passes'; + + # Test with META.json that has unsatisfied dependencies + my $meta_json_bad_dir = tempdir( CLEANUP => 1 ); + open $fh, '>', "$meta_json_bad_dir/META.json" or die "Cannot create META.json: $!"; + print $fh <<'JSON'; +{ + "abstract": "Test plugin", + "author": ["Test "], + "dynamic_config": 0, + "generated_by": "Test", + "license": ["gpl_3"], + "meta-spec": { "version": 2 }, + "name": "Test-Plugin", + "release_status": "stable", + "version": "1.0", + "prereqs": { + "runtime": { + "requires": { + "Nonexistent::Module::ABC": "1.0" + } + } + } +} +JSON + close $fh; + throws_ok { $plugins->_check_dependencies($meta_json_bad_dir) } + qr/Unmet dependencies:/, + 'META.json with unmet dependencies - dies'; + + # Test that multiple unmet dependencies are all reported + my $multi_bad_dir = tempdir( CLEANUP => 1 ); + open $fh, '>', "$multi_bad_dir/cpanfile" or die "Cannot create cpanfile: $!"; + print $fh "requires 'Nonexistent::ModuleA';\n"; + print $fh "requires 'Nonexistent::ModuleB';\n"; + close $fh; + throws_ok { $plugins->_check_dependencies($multi_bad_dir) } + qr/Nonexistent::ModuleA.*Nonexistent::ModuleB/s, + 'Multiple unmet dependencies are all reported'; +}; + +subtest 'InstallPlugins() with from parameter tests' => sub { + + plan tests => 6; + + $schema->storage->txn_begin; + + t::lib::Mocks::mock_config( 'enable_plugins', 1 ); + + # Create a temporary plugins directory for this test + my $test_plugins_dir = tempdir( CLEANUP => 1 ); + t::lib::Mocks::mock_config( 'pluginsdir', $test_plugins_dir ); + + my $plugins = Koha::Plugins->new( { enable_plugins => 1 } ); + + # Test 1: Files are copied from staging to plugins dir + my $staging_dir = tempdir( CLEANUP => 1 ); + mkdir "$staging_dir/Koha"; + mkdir "$staging_dir/Koha/Plugin"; + open my $fh, '>', "$staging_dir/Koha/Plugin/TestStaging.pm" or die $!; + print $fh "package Koha::Plugin::TestStaging;\n1;\n"; + close $fh; + + $plugins->InstallPlugins( { from => $staging_dir, verbose => 0 } ); + ok( -f "$test_plugins_dir/Koha/Plugin/TestStaging.pm", 'Plugin file copied to plugins directory' ); + + # Test 2: cpanfile is NOT copied + my $staging_dir2 = tempdir( CLEANUP => 1 ); + mkdir "$staging_dir2/Koha"; + mkdir "$staging_dir2/Koha/Plugin"; + open $fh, '>', "$staging_dir2/Koha/Plugin/TestStaging2.pm" or die $!; + print $fh "package Koha::Plugin::TestStaging2;\n1;\n"; + close $fh; + open $fh, '>', "$staging_dir2/cpanfile" or die $!; + print $fh "requires 'Modern::Perl';\n"; + close $fh; + + $plugins->InstallPlugins( { from => $staging_dir2, verbose => 0 } ); + ok( -f "$test_plugins_dir/Koha/Plugin/TestStaging2.pm", 'Plugin file copied' ); + ok( !-f "$test_plugins_dir/cpanfile", 'cpanfile is NOT copied to plugins directory' ); + + # Test 3: META.json and META.yml are NOT copied + my $staging_dir3 = tempdir( CLEANUP => 1 ); + mkdir "$staging_dir3/Koha"; + mkdir "$staging_dir3/Koha/Plugin"; + open $fh, '>', "$staging_dir3/Koha/Plugin/TestStaging3.pm" or die $!; + print $fh "package Koha::Plugin::TestStaging3;\n1;\n"; + close $fh; + + # Create valid META.json (CPAN::Meta 2.0 format) + open $fh, '>', "$staging_dir3/META.json" or die $!; + print $fh <<'JSON'; +{ + "abstract": "Test", + "author": ["Test "], + "dynamic_config": 0, + "generated_by": "Test", + "license": ["gpl_3"], + "meta-spec": { "version": 2 }, + "name": "Test", + "release_status": "stable", + "version": "1.0" +} +JSON + close $fh; + + # Create valid META.yml (CPAN::Meta 1.4 format) + open $fh, '>', "$staging_dir3/META.yml" or die $!; + print $fh <<'YAML'; +meta-spec: + version: 1.4 +name: Test +version: 1.0 +abstract: Test +author: + - Test +license: perl +YAML + close $fh; + + $plugins->InstallPlugins( { from => $staging_dir3, verbose => 0 } ); + ok( !-f "$test_plugins_dir/META.json", 'META.json is NOT copied to plugins directory' ); + ok( !-f "$test_plugins_dir/META.yml", 'META.yml is NOT copied to plugins directory' ); + + # Test 4: Trailing slash in path is handled correctly + my $staging_dir4 = tempdir( CLEANUP => 1 ); + mkdir "$staging_dir4/Koha"; + mkdir "$staging_dir4/Koha/Plugin"; + open $fh, '>', "$staging_dir4/Koha/Plugin/TestStaging4.pm" or die $!; + print $fh "package Koha::Plugin::TestStaging4;\n1;\n"; + close $fh; + + # Pass path with trailing slash + $plugins->InstallPlugins( { from => "$staging_dir4/", verbose => 0 } ); + ok( + -f "$test_plugins_dir/Koha/Plugin/TestStaging4.pm", + 'Plugin file copied correctly with trailing slash in from path' + ); + + $schema->storage->txn_rollback; +}; + $schema->storage->txn_rollback; #!/usr/bin/perl -- 2.52.0