package tests::PluginManagerTest; use strict; use base qw/ Lire::Test::TestCase /; use Lire::PluginManager; use Lire::DlfAnalyser; use Lire::Utils qw/tempdir create_file /; use File::Path qw/mkpath rmtree/; use File::Basename; use Cwd qw/realpath/; use Lire::Test::Mock; sub set_up { my $self = $_[0]; $self->SUPER::set_up(); $self->{'_old_mgr'} = $Lire::PluginManager::instance; $Lire::PluginManager::instance = $self->{'mgr'}=new Lire::PluginManager(); $self->{'tmpdir'} = tempdir( "PluginManager_XXXXXX", 'CLEANUP' => 1 ); return; } sub tear_down { my $self = $_[0]; $self->SUPER::tear_down(); $Lire::PluginManager::instance = $self->{'_old_mgr'}; rmtree( $self->{'tmpdir'} ); return; } sub test_instance { my $self = $_[0]; $self->assert_str_equals( $self->{'mgr'}, Lire::PluginManager->instance() ); } sub test_check_type { my $self = $_[0]; local %Lire::PluginManager::plugin_types = ( 'a_type' => 'Package', 'b_type' => 'AnotherPackage' ); $self->assert( Lire::PluginManager::check_type( 'a_type' ) ); $self->assert_dies( qr/missing 'type' parameter/, sub { Lire::PluginManager::check_type( undef ) } ); $self->assert_dies( qr/'type' parameter should be one of 'a_type' or 'b_type': 'bad'/, sub { Lire::PluginManager::check_type( 'bad' ) } ); } sub test_plugin_names { my $self = $_[0]; my $mgr = $self->{'mgr'}; %{$mgr->{'output_format'}} = ( 'test1' => undef, 'test2' => undef ); $self->assert_deep_equals( [ 'test1', 'test2' ], [ sort @{ $mgr->plugin_names( 'output_format' )} ] ); $self->assert_deep_equals( [ 'test1', 'test2' ], [ sort @{ Lire::PluginManager->plugin_names( 'output_format' )} ] ); } sub test_plugins { my $self = $_[0]; my $mgr = $self->{'mgr'}; %{$mgr->{'output_format'}} = ( 'test1' => 1, 'test2' => 2 ); $self->assert_deep_equals( [ 1, 2 ], [ sort @{ $mgr->plugins( 'output_format' )} ] ); $self->assert_deep_equals( [ 1, 2 ], [ sort @{ Lire::PluginManager->plugins( 'output_format' )} ] ); } sub test_has_plugin { my $self = $_[0]; my $mgr = $self->{'mgr'}; %{$mgr->{'output_format'}} = ( 'test1' => 1, 'test2' => 2 ); $self->assert( ! $mgr->has_plugin( 'dlf_converter', 'not_there' ) ); $self->assert( Lire::PluginManager->has_plugin( 'output_format', 'test1' ) ); } sub test_get_plugin { my $self = $_[0]; my $mgr = $self->{'mgr'}; %{$mgr->{'output_format'}} = ( 'test1' => 1, 'test2' => 2 ); $self->assert_num_equals( 1, $mgr->get_plugin( 'output_format', 'test1' ) ); $self->assert_num_equals( 2, Lire::PluginManager->get_plugin( 'output_format', 'test2' ) ); $self->assert_dies( qr/no 'dlf_converter' plugin 'test3' registered/, sub { $mgr->get_plugin( 'dlf_converter', 'test3' ) } ); } sub test_register_plugin { my $self = $_[0]; my $mgr = $self->{'mgr'}; $mgr->{'dlf_converter'}{'test'} = 1; my $plugin = new Lire::Test::Mock( 'Lire::Plugin', 'name' => 'test', 'type' => 'dlf_converter' ); $self->assert_dies( qr/'dlf_converter' plugin should be a 'Lire::DlfConverter' instance: 'Class::Inner/, sub { $mgr->register_plugin( $plugin ) } ); my $test = new Lire::Test::Mock( 'Lire::DlfConverter', 'name' => 'test', 'type' => 'dlf_converter' ); $self->assert_dies( qr/there is already a 'dlf_converter' plugin registered under name 'test'/, sub { $mgr->register_plugin( $test ) } ); my $unknown_type = new Lire::Test::Mock( 'Lire::DlfConverter', 'name' => 'test1', 'type' => 'bad_type' ); $self->assert_dies( qr/plugin 'test1' has an unknown type: 'bad_type'/, sub { $mgr->register_plugin( $unknown_type ) } ); my $test2 = new Lire::Test::Mock( 'Lire::DlfConverter', 'name' => 'test2', 'type' => 'dlf_converter' ); Lire::PluginManager->register_plugin( $test2 ); $self->assert_str_equals( $test2, $mgr->{'dlf_converter'}{'test2'} ); } sub test_unregister_plugin { my $self = $_[0]; my $mgr = $self->{'mgr'}; %{$mgr->{'output_format'}} = ( 'test1' => 1, 'test2' => 2 ); $mgr->unregister_plugin( 'output_format', 'test1' ); $self->assert_null( $mgr->{'output_format'}{'test1'} ); Lire::PluginManager->unregister_plugin( 'output_format', 'test2' ); $self->assert_null( $mgr->{'output_format'}{'test2'} ); $self->assert_dies( qr/no 'dlf_converter' plugin 'test3' registered/, sub { $mgr->unregister_plugin( 'dlf_converter', 'test3' ) } ); } sub test_register_default_plugins { my $self = $_[0]; mkpath( [ $self->{'tmpdir'} . "/dir1", $self->{'tmpdir'} . "/dir2", ], 0, 0755 ) == 2 or $self->error( "mkpath failed: $!\n" ); create_file( "$self->{'tmpdir'}/dir1/failing", 'die "error here\n"' ); create_file( "$self->{'tmpdir'}/dir2/a_plugin", <register_plugin( bless {}, 'converter' ); return; EOF my @warn = (); local $SIG{'__WARN__'} = sub { push @warn, join( "", @_ )}; $self->{'cfg'}{'plugins_init_path'} = [ "$self->{'tmpdir'}/dir1", "$self->{'tmpdir'}/dir2" ]; no warnings 'redefine'; local *Lire::PluginManager::_load_dlf_adapters = sub { $_[0]{'_load_dlf_adapters'} = 1 }; local *Lire::PluginManager::_create_old_dlf_adapters = sub { $_[0]{'_create_old_dlf_adapters'} = 1 }; Lire::PluginManager->register_default_plugins(); $self->annotate( @warn ); $self->assert_isa( 'Lire::DlfConverter', $self->{'mgr'}{'dlf_converter'}{'test'} ); $self->assert_num_equals( 1, scalar @warn ); $self->assert_matches( qr!error in initialiser '$self->{'tmpdir'}/dir1/failing': error here!, $warn[0] ); $self->assert_num_equals( 1, $self->{'mgr'}{'_load_dlf_adapters'} ); $self->assert_num_equals( 1, $self->{'mgr'}{'_create_old_dlf_adapters'} ); } sub test_init_files { my $self = $_[0]; my $dirs = [ $self->{'tmpdir'} . "/dir1", $self->{'tmpdir'} . "/dir2", $self->{'tmpdir'} . "/dir1", ]; mkpath( $dirs, 0, 0755 ) == 2 or $self->error( "mkpath failed: $!\n" ); my @files = ( $self->{'tmpdir'} . "/dir1/test", $self->{'tmpdir'} . "/dir1/test3", $self->{'tmpdir'} . "/dir2/test2", ); foreach my $f ( @files ) { create_file( $f ); } $self->assert_deep_equals( \@files, Lire::PluginManager->_init_files( $dirs ) ); } sub test_load_dlf_adapters { my $self = $_[0]; my $dirs = [ $self->{'tmpdir'} . "/dlf_converters1", $self->{'tmpdir'} . "/dlf_converters2" ]; mkpath( $dirs, 0, 0755 ) == 2 or $self->error( "mkpath failed: $!\n" ); $self->{'cfg'}{'lr_converters_init_path'} = $dirs; create_file( $self->{'tmpdir'} . "/dlf_converters1/test1" ); chmod 0000, $self->{'tmpdir'} . "/dlf_converters1/test1" or $self->error( "chmod failed: $!\n" ); create_file( $self->{'tmpdir'} . "/dlf_converters1/test2", <<'EOF' ); use strict; $x = 1; EOF create_file( $self->{'tmpdir'} . "/dlf_converters1/test3", <<'EOF' ); package Converter; use base qw/Lire::DlfConverter/; sub new { bless { 'name' => $_[1] }, $_[0]; } sub name { $_[0]{'name'} }; return ( new Converter( 'test1' ), new Converter( 'test2' ) ); EOF create_file( $self->{'tmpdir'} . "/dlf_converters2/test4", <<'EOF' ); return bless {}, "Test"; EOF my @msg = (); local $SIG{'__WARN__'} = sub { push @msg, join "", @_; $self->annotate( $msg[-1] ); }; $self->{'mgr'}->_load_dlf_adapters(); # Reset the permission, so it can be deleted with rmtree() chmod 0644, $self->{'tmpdir'} . "/dlf_converters1/test1" or $self->error( "chmod failed: $!\n" ); $self->assert( @msg == 3, "expected 3 warnings" ); $self->assert_matches( qr/error reading DLF converter/, $msg[0] ); $self->assert_matches( qr/error while running initializer/, $msg[1] ); $self->assert_matches( qr/didn't return a Lire::DlfConverter/, $msg[2] ); $self->assert_isa( 'Converter', $self->{'mgr'}{'dlf_converter'}{'test1'} ); $self->assert_isa( 'Converter', $self->{'mgr'}{'dlf_converter'}{'test2'} ); } sub test_parse_map_file { my $self = $_[0]; my $address_file = $self->{'tmpdir'} . "/address.cf"; create_file ( $address_file, <{'mgr'}->_parse_old_map_file( $address_file ); $self->annotate( join "\n", @msg ); $self->assert( @msg == 1, "expected one warning, got " . scalar @msg ); $self->assert_matches( qr/can't parse line 5/, $msg[0] ); $self->assert_deep_equals( { 'service' => 'superservice', 'service1' => 'schema1', }, $services ); } sub test_create_old_dlf_adapters { my $self = $_[0]; my $address_file = $self->{'tmpdir'} . "/address.cfg"; $self->{'cfg'}{'lr_old_convertors_dir'} = $self->{'tmpdir'}; $self->{'cfg'}{'lr_old_address_file'} = $address_file; create_file( "$self->{'tmpdir'}/service12dlf" ); create_file( "$self->{'tmpdir'}/service22dlf" ); create_file( "$self->{'tmpdir'}/service42dlf" ); chmod( 0755, map { "$self->{'tmpdir'}/" . $_ . "2dlf" } qw/service1 service2/) == 2 or $self->error( "chmod failed" ); create_file( $address_file, <{'cfg'}{'lr_schemas_path'} = [ realpath(dirname( __FILE__ )) . "/schemas" ]; my @msg = (); local $SIG{'__WARN__'} = sub { my $m = join "", @_; $self->annotate( $m); push @msg, $m; }; $self->{'mgr'}->_create_old_dlf_adapters(); @msg = sort @msg; my @warnings = ( qr/can't find executable service32dlf/, qr/can't find executable service42dlf/, qr/invalid superservice/ ); $self->assert_num_equals( scalar @msg, scalar @warnings ); for ( my $i=0; $i < @warnings; $i++ ) { $self->assert_matches( $warnings[$i], $msg[$i] ); } my @converters = ( "service1" ); $self->assert_isa( 'Lire::OldDlfAdapter', $self->{'mgr'}{'dlf_converter'}{'service1'} ); } sub set_up_fake_analysers { my $self = $_[0]; $self->{'mgr'}{'dlf_analyser'}{'extended'} = new Lire::Test::Mock( 'Lire::DlfAnalyser', 'name' => 'extended', 'src_schema' => 'test', 'dst_schema' => 'test-extended' ); $self->{'mgr'}{'dlf_analyser'}{'extended2'} = new Lire::Test::Mock( 'Lire::DlfAnalyser', 'name' => 'extended2', 'src_schema' => 'test', 'dst_schema' => 'test-extended', ); $self->{'mgr'}{'dlf_analyser'}{'derived'} = new Lire::Test::Mock( 'Lire::DlfAnalyser', 'name' => 'derived', 'src_schema' => 'test-derived', 'dst_schema' => 'another-schema' ); return; } sub test_analysers_by_src { my $self = $_[0]; $self->set_up_fake_analysers(); $self->assert_deep_equals( [], $self->{'mgr'}->analysers_by_src( 'wawa' )); my @analysers = sort { $a->name() cmp $b->name() } @{$self->{'mgr'}->analysers_by_src( 'test' )}; $self->assert_deep_equals( [ $self->{'mgr'}{'dlf_analyser'}{'extended'}, $self->{'mgr'}{'dlf_analyser'}{'extended2'}], \@analysers ); } sub test_analysers_by_dst { my $self = $_[0]; $self->set_up_fake_analysers(); $self->assert_deep_equals( [], $self->{'mgr'}->analysers_by_dst( 'wawa' )); my @analysers = sort { $a->name() cmp $b->name() } @{$self->{'mgr'}->analysers_by_dst( 'test-extended' )}; $self->assert_deep_equals( [ $self->{'mgr'}{'dlf_analyser'}{'extended'}, $self->{'mgr'}{'dlf_analyser'}{'extended2'}], \@analysers ); } 1;