From fb0e3f3c83271df2ea67240fd198c952a031a45f Mon Sep 17 00:00:00 2001 From: Alex Sassmannshausen Date: Mon, 16 Oct 2017 10:47:14 +0200 Subject: [PATCH] Bug 7317: Add unit tests & fix, add comments to Illrequest.pm. * Koha/Illrequest.pm: Add code commentary. (_backend_capability): We need to invoke our code ref. * Koha/Illrequest/Config.pm: Correct reference to potentially uninstantiated $reply_date variable. Minor improvements as result of new tests. * t/db_dependent/Illrequest/Config.t: Improve tests. * t/db_dependent/Illrequestattributes.t: Improve tests. * t/db_dependent/Illrequests.t: Improve tests. --- Koha/Illrequest.pm | 110 +++-- Koha/Illrequest/Config.pm | 21 +- t/db_dependent/Illrequest/Config.t | 733 ++++++++++++++++++------------- t/db_dependent/Illrequestattributes.t | 63 +++ t/db_dependent/Illrequests.t | 792 ++++++++++++++++++++++++++++++++++ 5 files changed, 1365 insertions(+), 354 deletions(-) create mode 100644 t/db_dependent/Illrequestattributes.t create mode 100644 t/db_dependent/Illrequests.t diff --git a/Koha/Illrequest.pm b/Koha/Illrequest.pm index d91be8e5b1..cc5959ce78 100644 --- a/Koha/Illrequest.pm +++ b/Koha/Illrequest.pm @@ -166,6 +166,17 @@ This is a helper method to invoke optional capabilities in the backend. If the capability named by $name is not supported, return 0, else invoke it, passing $args along with the invocation, and return its return value. +NOTE: this module suffers from a confusion in termninology: + +in _backend_capability, the notion of capability refers to an optional feature +that is implemented in core, but might not be supported by a given backend. + +in capabilities & custom_capability, capability refers to entries in the +status_graph (after union between backend and core). + +The easiest way to fix this would be to fix the terminology in +capabilities & custom_capability and their callers. + =cut sub _backend_capability { @@ -177,7 +188,7 @@ sub _backend_capability { return 0; }; if ( $capability ) { - return $capability($args); + return &{$capability}($args); } else { return 0; } @@ -213,6 +224,13 @@ sub metadata { =head3 _core_status_graph + my $core_status_graph = $illrequest->_core_status_graph; + +Returns ILL module's default status graph. A status graph defines the list of +available actions at any stage in the ILL workflow. This is for instance used +by the perl script & template to generate the correct buttons to display to +the end user at any given point. + =cut sub _core_status_graph { @@ -296,6 +314,27 @@ sub _core_status_graph { }; } +=head3 _core_status_graph + + my $status_graph = $illrequest->_core_status_graph($origin, $new_graph); + +Return a new status_graph, the result of merging $origin & new_graph. This is +operation is a union over the sets defied by the two graphs. + +Each entry in $new_graph is added to $origin. We do not provide a syntax for +'subtraction' of entries from $origin. + +Whilst it is not intended that this works, you can override entries in $origin +with entries with the same key in $new_graph. This can lead to problematic +behaviour when $new_graph adds an entry, which modifies a dependent entry in +$origin, only for the entry in $origin to be replaced later with a new entry +from $new_graph. + +NOTE: this procedure does not "re-link" entries in $origin or $new_graph, +i.e. each of the graphs need to be correct at the outset of the operation. + +=cut + sub _status_graph_union { my ( $self, $core_status_graph, $backend_status_graph ) = @_; # Create new status graph with: @@ -354,6 +393,17 @@ Example return value: { create => "Create Request", confirm => "Progress Request" } +NOTE: this module suffers from a confusion in termninology: + +in _backend_capability, the notion of capability refers to an optional feature +that is implemented in core, but might not be supported by a given backend. + +in capabilities & custom_capability, capability refers to entries in the +status_graph (after union between backend and core). + +The easiest way to fix this would be to fix the terminology in +capabilities & custom_capability and their callers. + =cut sub capabilities { @@ -377,6 +427,17 @@ sub capabilities { Return the result of invoking $CANDIDATE on this request's backend with $PARAMS, or 0 if $CANDIDATE is an unknown method on backend. +NOTE: this module suffers from a confusion in termninology: + +in _backend_capability, the notion of capability refers to an optional feature +that is implemented in core, but might not be supported by a given backend. + +in capabilities & custom_capability, capability refers to entries in the +status_graph (after union between backend and core). + +The easiest way to fix this would be to fix the terminology in +capabilities & custom_capability and their callers. + =cut sub custom_capability { @@ -413,7 +474,7 @@ sub available_actions { sub mark_completed { my ( $self ) = @_; - $self->status('COMP')->store unless ( $permitted ); + $self->status('COMP')->store; return { error => 0, status => '', @@ -585,36 +646,6 @@ sub expandTemplate { #### Abstract Imports -=head3 getCensorNotesStaff - - my $bool = $abstract->getCensorNotesStaff; - -Return a boolean indicating whether we should be censoring staff notes or not, -as determined by our configuration file. - -=cut - -sub getCensorNotesStaff { - my ( $self ) = @_; - my $censorship = $self->_config->censorship; - return $censorship->{censor_notes_staff}; -} - -=head3 getDisplayReplyDate - - my 0 = $abstract->getDisplayReplyDate; - -Return a 0 if we want to hide it or 1 if not. - -=cut - -sub getDisplayReplyDate { - my ( $self ) = @_; - my $censorship = $self->_config->censorship; - # If censor is yes, don't display and vice versa. - return ( $censorship->{censor_reply_date} ) ? 0 : 1; -} - =head3 getLimits my $limit_rules = $abstract->getLimits( { @@ -629,7 +660,6 @@ or for the default, we must define fall-back values here. =cut -# FIXME: Needs unit tests! sub getLimits { my ( $self, $params ) = @_; my $limits = $self->_config->getLimitRules($params->{type}); @@ -683,13 +713,12 @@ LimitRules are derived from koha-conf.xml: =cut -# FIXME: Needs unit tests! sub check_limits { my ( $self, $params ) = @_; my $patron = $params->{patron}; my $branchcode = $params->{librarycode} || $patron->branchcode; - # Establish rules + # Establish maximum number of allowed requests my ( $branch_rules, $brw_rules ) = ( $self->getLimits( { type => 'branch', @@ -700,9 +729,9 @@ sub check_limits { value => $patron->categorycode, } ), ); - # Almost there, but category code didn't quite work. my ( $branch_limit, $brw_limit ) = ( $branch_rules->{count}, $brw_rules->{count} ); + # Establish currently existing requests my ( $branch_count, $brw_count ) = ( $self->_limit_counter( $branch_rules->{method}, { branchcode => $branchcode } @@ -723,7 +752,6 @@ sub check_limits { } } -# FIXME: Needs unit tests! sub _limit_counter { my ( $self, $method, $target ) = @_; @@ -737,7 +765,7 @@ sub _limit_counter { ] }); } else { # assume 'active' - # FIXME: This status list is ugly. There should be a method in config + # XXX: This status list is ugly. There should be a method in config # to return these. $where = { status => { -not_in => [ 'QUEUED', 'COMP' ] } }; $resultset = Koha::Illrequests->search({ %{$target}, %{$where} }); @@ -888,7 +916,6 @@ file. sub id_prefix { my ( $self ) = @_; - # FIXME: can we automatically use borrowernumber as borrower? my $brw = $self->patron; my $brw_cat = "dummy"; $brw_cat = $brw->categorycode @@ -911,9 +938,10 @@ Return $params, modified to reflect our censorship requirements. sub _censor { my ( $self, $params ) = @_; - $params->{censor_notes_staff} = $self->getCensorNotesStaff + my $censorship = $self->_config->censorship; + $params->{censor_notes_staff} = $censorship->{censor_notes_staff} if ( $params->{opac} ); - $params->{display_reply_date} = $self->getDisplayReplyDate; + $params->{display_reply_date} = ( $censorship->{censor_reply_date} ) ? 0 : 1; return $params; } diff --git a/Koha/Illrequest/Config.pm b/Koha/Illrequest/Config.pm index bd8edf041d..02740a1c34 100644 --- a/Koha/Illrequest/Config.pm +++ b/Koha/Illrequest/Config.pm @@ -62,13 +62,13 @@ ILL configuration file. =cut sub new { - my ( $class, $test ) = @_; + my ( $class ) = @_; my $self = {}; $self->{configuration} = _load_configuration( C4::Context->config("interlibrary_loans"), C4::Context->preference("UnmediatedILL") - ) unless ( $test ); + ); bless $self, $class; @@ -107,7 +107,7 @@ sub backend_dir { =head3 partner_code - $partner_code = $config->partner_code($new_path); + $partner_code = $config->partner_code($new_code); $partner_code = $config->partner_code; Standard setter/accessor for our partner_code. @@ -286,15 +286,12 @@ sub _load_configuration { }); # Censorship - my $staff_comments = $xml_config->{staff_request_comments}; + my $staff_comments = $xml_config->{staff_request_comments} || 0; $configuration->{censorship}->{censor_notes_staff} = 1 if ( $staff_comments && 'hide' eq $staff_comments ); - my $reply_date = $xml_config->{reply_date}; - if ( 'hide' eq $reply_date ) { - $configuration->{censorship}->{censor_reply_date} = 1; - } else { - $configuration->{censorship}->{censor_reply_date} = $reply_date; - } + my $reply_date = $xml_config->{reply_date} || 0; + $configuration->{censorship}->{censor_reply_date} = 1 + if ( $reply_date && 'hide' eq $reply_date ); # ILL Partners $configuration->{partner_code} = $xml_config->{partner_code} || 'ILLLIBS'; @@ -313,7 +310,7 @@ $PARAMS is a hashref with the following elements: - unit: the part of the configuration we are parsing. - id: the name within which we will store the parsed unit in config. - config: the configuration we are augmenting. -- type: the type config unit we are parsing. Assumed to be 'default'. +- type: the type of config unit we are parsing. Assumed to be 'default'. Read `unit', and augment `config' with these under `id'. @@ -330,6 +327,8 @@ sub _load_unit_config { my $id = $params->{id}; my $config = $params->{config}; my $type = $params->{type}; + die "TYPE should be either 'branch' or 'brw_cat' if ID is not 'default'." + if ( $id ne 'default' && ( $type ne 'branch' && $type ne 'brw_cat') ); return $config unless $id; if ( $unit->{api_key} && $unit->{api_auth} ) { diff --git a/t/db_dependent/Illrequest/Config.t b/t/db_dependent/Illrequest/Config.t index df2bcac7aa..f44fa85cfd 100644 --- a/t/db_dependent/Illrequest/Config.t +++ b/t/db_dependent/Illrequest/Config.t @@ -17,328 +17,457 @@ use Modern::Perl; +use Koha::Database; +use t::lib::Mocks; +use t::lib::TestBuilder; +use Test::MockObject; use Test::Exception; -use Test::More; -use Test::Warn; -# Some data structures that will be repeatedly referenced -my $defaults = { - api_key => "564euie", - api_auth => "unidaenudvnled", -}; -my $application = { - key => "6546uedrun", - auth => "edutrineadue", -}; -# Simulate $from_xml -my $params = { - application => $application, - backend => "Dummy", - configuration => $defaults, - reply_date => "hide", - staff_request_comments => "hide", +use Test::More tests => 5; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; +use_ok('Koha::Illrequest::Config'); + +my $base_limits = { + branch => { CPL => { count => 1, method => 'annual' } }, + brw_cat => { A => { count => -1, method => 'active' } }, + default => { count => 10, method => 'annual' }, }; -my $first_branch = { - code => "test", api_key => "dphügnpgüffq", api_auth => "udrend" + +my $base_censorship = { censor_notes_staff => 1, censor_reply_date => 1 }; + +subtest 'Basics' => sub { + + plan tests => 19; + + $schema->storage->txn_begin; + + t::lib::Mocks::mock_preference("UnmediatedILL", 0); + t::lib::Mocks::mock_config("interlibrary_loans", {}); + + my $config = Koha::Illrequest::Config->new; + isa_ok($config, "Koha::Illrequest::Config", + "Correctly create and load a config object."); + + # backend: + is($config->backend, undef, "backend: Undefined backend is undefined."); + is($config->backend("Mock"), "Mock", "backend: setter works."); + is($config->backend, "Mock", "backend: setter is persistent."); + + # backend_dir: + is($config->backend_dir, undef, "backend_dir: Undefined backend_dir is undefined."); + is($config->backend_dir("/tmp/"), "/tmp/", "backend_dir: setter works."); + is($config->backend_dir, "/tmp/", "backend_dir: setter is persistent."); + + # partner_code: + is($config->partner_code, "ILLLIBS", "partner_code: Undefined partner_code is undefined."); + is($config->partner_code("ILLLIBSTST"), "ILLLIBSTST", "partner_code: setter works."); + is($config->partner_code, "ILLLIBSTST", "partner_code: setter is persistent."); + + # limits: + is_deeply($config->limits, {}, "limits: Undefined limits is empty hash."); + is_deeply($config->limits($base_limits), $base_limits, "limits: setter works."); + is_deeply($config->limits, $base_limits, "limits: setter is persistent."); + + # censorship: + is_deeply($config->censorship, { censor_notes_staff => 0, censor_reply_date => 0 }, + "censorship: Undefined censorship is default values."); + is_deeply($config->censorship($base_censorship), $base_censorship, "censorship: setter works."); + is_deeply($config->censorship, $base_censorship, "censorship: setter is persistent."); + + # getLimitRules + dies_ok( sub { $config->getLimitRules("FOO") }, "getLimitRules: die if not correct type."); + is_deeply($config->getLimitRules("brw_cat"), { + A => { count => -1, method => 'active' }, + default => { count => 10, method => 'annual' }, + }, "getLimitRules: fetch brw_cat limits."); + is_deeply($config->getLimitRules("branch"), { + CPL => { count => 1, method => 'annual' }, + default => { count => 10, method => 'annual' }, + }, "getLimitRules: fetch brw_cat limits."); + + $schema->storage->txn_rollback; }; -my $second_branch = { - code => "second", - api_key => "eduirn", - api_auth => "eudtireand", - request_limit => { count => "5" }, + +# _load_unit_config: + +subtest '_load_unit_config' => sub { + + plan tests => 10; + + $schema->storage->txn_begin; + + my $config = Koha::Illrequest::Config->new; + + dies_ok( + sub { Koha::Illrequest::Config::_load_unit_config({ + id => 'durineadu', type => 'baz' + }) }, + "_load_unit_config: die if ID is not default, and type is not branch or brw_cat." + ); + is_deeply( + Koha::Illrequest::Config::_load_unit_config({ + unit => {}, id => 'default', config => {}, test => 1 + }), {}, "_load_unit_config: invocation without id returns unmodified config." + ); + + is_deeply( + Koha::Illrequest::Config::_load_unit_config({ + unit => { api_key => 'foo', api_auth => 'bar' }, + id => "CPL", type => 'branch', config => {} + }), + { credentials => { api_keys => { CPL => { api_key => 'foo', api_auth => 'bar' } } } }, + "_load_unit_config: add auth values." + ); + + # Populate request_limits + is_deeply( + Koha::Illrequest::Config::_load_unit_config({ + unit => { request_limit => [ 'heelo', 1234 ] }, + id => "CPL", type => 'branch', config => {} + }), {}, "_load_unit_config: invalid request_limit structure." + ); + is_deeply( + Koha::Illrequest::Config::_load_unit_config({ + unit => { request_limit => { method => 'eudiren', count => '-5465' } }, + id => "CPL", type => 'branch', config => {} + }), {}, "_load_unit_config: invalid method & count." + ); + is_deeply( + Koha::Illrequest::Config::_load_unit_config({ + unit => { request_limit => { method => 'annual', count => 6 } }, + id => "default", config => {} + }), + { limits => { default => { method => 'annual', count => 6 } } }, + "_load_unit_config: correct default request_limits." + ); + + # Populate prefix + is_deeply( + Koha::Illrequest::Config::_load_unit_config({ + unit => { prefix => 'Foo-ill' }, + id => "default", config => {} + }), + { prefixes => { default => 'Foo-ill' } }, + "_load_unit_config: correct default prefix." + ); + is_deeply( + Koha::Illrequest::Config::_load_unit_config({ + unit => { prefix => 'Foo-ill' }, + id => "A", config => {}, type => 'brw_cat' + }), + { prefixes => { brw_cat => { A => 'Foo-ill' } } }, + "_load_unit_config: correct brw_cat prefix." + ); + + # Populate digital_recipient + is_deeply( + Koha::Illrequest::Config::_load_unit_config({ + unit => { digital_recipient => 'borrower' }, + id => "default", config => {} + }), + { digital_recipients => { default => 'borrower' } }, + "_load_unit_config: correct default digital_recipient." + ); + is_deeply( + Koha::Illrequest::Config::_load_unit_config({ + unit => { digital_recipient => 'branch' }, + id => "A", config => {}, type => 'brw_cat' + }), + { digital_recipients => { brw_cat => { A => 'branch' } } }, + "_load_unit_config: correct brw_cat digital_recipient." + ); + + $schema->storage->txn_rollback; }; -BEGIN { - use_ok('Koha::Illrequest::Config'); -} - -my $config = Koha::Illrequest::Config->new(1); # with test_mode enabled. -isa_ok($config, 'Koha::Illrequest::Config'); - -# _load_configuration -is_deeply( - Koha::Illrequest::Config::_load_configuration($params), - { - api_url => 'http://apitest.bldss.bl.uk', - backend => 'Dummy', - censorship => { - censor_notes_staff => 1, - censor_reply_date => 1, - }, - credentials => { - api_application => $application, - api_keys => { default => $defaults }, - }, - default_formats => {}, - digital_recipients => {}, - library_privileges => {}, - limits => {}, - prefixes => {}, - spec_file => undef, - }, - "Basic _load_configuration" -); - -$params->{configuration}->{request_limit}->{count} = 10; -is_deeply( - Koha::Illrequest::Config::_load_configuration($params), - { - api_url => 'http://apitest.bldss.bl.uk', - backend => 'Dummy', - censorship => { - censor_notes_staff => 1, - censor_reply_date => 1, - }, - credentials => { - api_application => $application, - api_keys => { - default => { - api_auth => $defaults->{api_auth}, - api_key => $defaults->{api_key}, - } +# _load_configuration: + +# We have already tested _load_unit_config, so we are reasonably confident +# that the per-branch, per-borrower_category & default sections parsing is +# good. +# +# Now we need to ensure that Arrays & Hashes are handled correctly, that +# censorship & ill partners are loaded correctly and that the backend +# directory is set correctly. + +subtest '_load_configuration' => sub { + + plan tests => 9; + + $schema->storage->txn_begin; + + my $config = Koha::Illrequest::Config->new; + + # Return basic configuration + is_deeply( + Koha::Illrequest::Config::_load_configuration({}, 0), + { + backend_directory => undef, + censorship => { + censor_notes_staff => 0, + censor_reply_date => 0, }, + limits => {}, + digital_recipients => {}, + prefixes => {}, + partner_code => 'ILLLIBS', + raw_config => {}, }, - default_formats => {}, - digital_recipients => {}, - library_privileges => {}, - limits => { default => { count => 10 } }, - prefixes => {}, - spec_file => undef, - }, - "Basic _load_configuration, with limit" -); - -$params->{configuration}->{branch} = $first_branch; -is_deeply( - Koha::Illrequest::Config::_load_configuration($params), - { - api_url => 'http://apitest.bldss.bl.uk', - backend => 'Dummy', - censorship => { - censor_notes_staff => 1, - censor_reply_date => 1, + "load_configuration: return the base configuration." + ); + + # Return correct backend_dir + is_deeply( + Koha::Illrequest::Config::_load_configuration({ backend_directory => '/tmp/' }, 0), + { + backend_directory => '/tmp/', + censorship => { + censor_notes_staff => 0, + censor_reply_date => 0, + }, + limits => {}, + digital_recipients => {}, + prefixes => {}, + partner_code => 'ILLLIBS', + raw_config => { backend_directory => '/tmp/' }, }, - credentials => { - api_keys => { - default => { - api_key => $defaults->{api_key}, - api_auth => $defaults->{api_auth}, - }, - $first_branch->{code} => { - api_key => $first_branch->{api_key}, - api_auth => $first_branch->{api_auth}, - }, + "load_configuration: return the correct backend_dir." + ); + + # Map over branch configs + my $xml_config = { + backend_directory => '/tmp/', + branch => [ + { code => '1', request_limit => { method => 'annual', count => 1 } }, + { code => '2', prefix => '2-prefix' }, + { code => '3', digital_recipient => 'branch' } + ] + }; + is_deeply( + Koha::Illrequest::Config::_load_configuration($xml_config, 0), + { + backend_directory => '/tmp/', + censorship => { + censor_notes_staff => 0, + censor_reply_date => 0, }, - api_application => $application, + limits => { branch => { 1 => { method => 'annual', count => 1 } } }, + digital_recipients => { branch => { 3 => 'branch' } }, + prefixes => { branch => { 2 => '2-prefix' } }, + partner_code => 'ILLLIBS', + raw_config => $xml_config, }, - default_formats => {}, - digital_recipients => {}, - library_privileges => {}, - limits => { default => { count => 10 } }, - prefixes => {}, - spec_file => undef, - }, - "Single Branch _load_configuration" -); - -$params->{configuration}->{branch} = [ $first_branch, $second_branch ]; -is_deeply( - Koha::Illrequest::Config::_load_configuration($params), - { - api_url => 'http://apitest.bldss.bl.uk', - credentials => { - api_keys => { - default => { - api_key => $defaults->{api_key}, - api_auth => $defaults->{api_auth}, - }, - $first_branch->{code} => { - api_key => $first_branch->{api_key}, - api_auth => $first_branch->{api_auth}, - }, - $second_branch->{code} => { - api_key => $second_branch->{api_key}, - api_auth => $second_branch->{api_auth}, - }, + "load_configuration: multi branch config parsed correctly." + ); + # Single branch config + $xml_config = { + backend_directory => '/tmp/', + branch => { + code => '1', + request_limit => { method => 'annual', count => 1 }, + prefix => '2-prefix', + digital_recipient => 'branch', + } + }; + is_deeply( + Koha::Illrequest::Config::_load_configuration($xml_config, 0), + { + backend_directory => '/tmp/', + censorship => { + censor_notes_staff => 0, + censor_reply_date => 0, }, - api_application => $application, + limits => { branch => { 1 => { method => 'annual', count => 1 } } }, + digital_recipients => { branch => { 1 => 'branch' } }, + prefixes => { branch => { 1 => '2-prefix' } }, + partner_code => 'ILLLIBS', + raw_config => $xml_config, }, - backend => 'Dummy', - censorship => { - censor_notes_staff => 1, - censor_reply_date => 1, + "load_configuration: single branch config parsed correctly." + ); + + # Map over borrower_category settings + $xml_config = { + backend_directory => '/tmp/', + borrower_category => [ + { code => 'A', request_limit => { method => 'annual', count => 1 } }, + { code => 'B', prefix => '2-prefix' }, + { code => 'C', digital_recipient => 'branch' } + ] + }; + is_deeply( + Koha::Illrequest::Config::_load_configuration($xml_config, 0), + { + backend_directory => '/tmp/', + censorship => { + censor_notes_staff => 0, + censor_reply_date => 0, + }, + limits => { brw_cat => { A => { method => 'annual', count => 1 } } }, + digital_recipients => { brw_cat => { C => 'branch' } }, + prefixes => { brw_cat => { B => '2-prefix' } }, + partner_code => 'ILLLIBS', + raw_config => $xml_config, }, - default_formats => {}, - digital_recipients => {}, - library_privileges => {}, - limits => { - default => {count => 10 }, - branch => { - $second_branch->{code} => {count => 5 }, + "load_configuration: multi borrower_category config parsed correctly." + ); + # Single borrower_category config + $xml_config = { + backend_directory => '/tmp/', + borrower_category => { + code => '1', + request_limit => { method => 'annual', count => 1 }, + prefix => '2-prefix', + digital_recipient => 'branch', + } + }; + is_deeply( + Koha::Illrequest::Config::_load_configuration($xml_config, 0), + { + backend_directory => '/tmp/', + censorship => { + censor_notes_staff => 0, + censor_reply_date => 0, }, + limits => { brw_cat => { 1 => { method => 'annual', count => 1 } } }, + digital_recipients => { brw_cat => { 1 => 'branch' } }, + prefixes => { brw_cat => { 1 => '2-prefix' } }, + partner_code => 'ILLLIBS', + raw_config => $xml_config, }, - prefixes => {}, - spec_file => undef, - }, - "Multi Branch _load_configuration" -); + "load_configuration: single borrower_category config parsed correctly." + ); -dies_ok { Koha::Illrequest::Config::_load_configuration($params, 1) } - "Unmediated, missing config _load_configuration"; - -$params->{configuration}->{default_formats} = { - format => 1, quality => 1, quantity => 1, service => 1, speed => 1 -}; -is_deeply( - Koha::Illrequest::Config::_load_configuration($params, 1), - { - api_url => 'http://apitest.bldss.bl.uk', - backend => 'Dummy', - censorship => { - censor_notes_staff => 1, - censor_reply_date => 1, - }, - credentials => { - api_keys => { - default => { - api_key => $defaults->{api_key}, - api_auth => $defaults->{api_auth}, - }, - $first_branch->{code} => { - api_key => $first_branch->{api_key}, - api_auth => $first_branch->{api_auth}, - }, - $second_branch->{code} => { - api_key => $second_branch->{api_key}, - api_auth => $second_branch->{api_auth}, - }, + # Default Configuration + $xml_config = { + backend_directory => '/tmp/', + request_limit => { method => 'annual', count => 1 }, + prefix => '2-prefix', + digital_recipient => 'branch', + }; + is_deeply( + Koha::Illrequest::Config::_load_configuration($xml_config, 0), + { + backend_directory => '/tmp/', + censorship => { + censor_notes_staff => 0, + censor_reply_date => 0, }, - api_application => $application, + limits => { default => { method => 'annual', count => 1 } }, + digital_recipients => { default => 'branch' }, + prefixes => { default => '2-prefix' }, + partner_code => 'ILLLIBS', + raw_config => $xml_config, }, - default_formats => { - default => { - format => 1, - quality => 1, - quantity => 1, - service => 1, - speed => 1 - } + "load_configuration: parse the default configuration." + ); + + # Censorship + $xml_config = { + backend_directory => '/tmp/', + staff_request_comments => 'hide', + reply_date => 'hide' + }; + is_deeply( + Koha::Illrequest::Config::_load_configuration($xml_config, 0), + { + backend_directory => '/tmp/', + censorship => { + censor_notes_staff => 1, + censor_reply_date => 1, + }, + limits => {}, + digital_recipients => {}, + prefixes => {}, + partner_code => 'ILLLIBS', + raw_config => $xml_config, }, - digital_recipients => {}, - library_privileges => {}, - limits => { - default => {count => 10 }, - branch => { - $second_branch->{code} => {count => 5 }, + "load_configuration: parse censorship settings configuration." + ); + + # Partner library category + is_deeply( + Koha::Illrequest::Config::_load_configuration({ partner_code => 'FOOBAR' }), + { + backend_directory => undef, + censorship => { + censor_notes_staff => 0, + censor_reply_date => 0, }, + limits => {}, + digital_recipients => {}, + prefixes => {}, + partner_code => 'FOOBAR', + raw_config => { partner_code => 'FOOBAR' }, }, - prefixes => {}, - spec_file => undef, - }, - "default_formats, default only _load_configuration" -); - -# getDefaultFormats -dies_ok { $config->getLimitRules('wrongType') } - "Faulty getDefaultFormats"; - -$config->{configuration} = - Koha::Illrequest::Config::_load_configuration($params); -is_deeply( - $config->getDefaultFormats('brw_cat'), - { - default => { - format => 1, - quality => 1, - quantity => 1, - service => 1, - speed => 1 - } - }, - "Default getDefaultFormats" -); - -# getLimitRules -dies_ok { $config->getLimitRules('wrongType') } - "Faulty getLimitRules"; - -$config->{configuration} = - Koha::Illrequest::Config::_load_configuration($params); -is_deeply( - $config->getLimitRules('branch'), - { - default => { count => 10 }, - second => { count => 5 }, - }, - "second branch getLimitRules" -); - -is_deeply( - $config->getLimitRules('brw_cat'), - { - default => { count => 10 }, - }, - "empty brw_cat getLimitRules" -); - -# getCredentials -$params = { - application => $application, - backend => 'Dummy', - configuration => {}, - reply_date => "hide", - staff_request_comments => "hide", + "load_configuration: Set partner code." + ); + + $schema->storage->txn_rollback; }; -$config->{configuration} = - Koha::Illrequest::Config::_load_configuration($params); -is_deeply( - $config->getCredentials, - { - api_key => 0, - api_key_auth => 0, - api_application => $application->{key}, - api_application_auth => $application->{auth}, - }, - "getCredentials, no creds, just App." -); - -$params->{configuration} = $defaults; -$config->{configuration} = - Koha::Illrequest::Config::_load_configuration($params), -is_deeply( - $config->getCredentials, - { - api_key => $defaults->{api_key}, - api_key_auth => $defaults->{api_auth}, - api_application => $application->{key}, - api_application_auth => $application->{auth}, - }, - "getCredentials, default creds & App." -); - -$params->{configuration}->{branch} = $first_branch; -$config->{configuration} = - Koha::Illrequest::Config::_load_configuration($params), -is_deeply( - $config->getCredentials($first_branch->{code}), - { - api_key => $first_branch->{api_key}, - api_key_auth => $first_branch->{api_auth}, - api_application => $application->{key}, - api_application_auth => $application->{auth}, - }, - "getCredentials, $first_branch->{code} creds & App." -); - -is_deeply( - $config->getCredentials("random"), - { - api_key => $defaults->{api_key}, - api_key_auth => $defaults->{api_auth}, - api_application => $application->{key}, - api_application_auth => $application->{auth}, - }, - "getCredentials, fallback creds & app." -); - -done_testing; + + +subtest 'Final tests' => sub { + + plan tests => 10; + + $schema->storage->txn_begin; + + t::lib::Mocks::mock_preference("UnmediatedILL", 0); + t::lib::Mocks::mock_config("interlibrary_loans", {}); + + my $config = Koha::Illrequest::Config->new; + + # getPrefixes (error & undef): + dies_ok( sub { $config->getPrefixes("FOO") }, "getPrefixes: die if not correct type."); + is_deeply($config->getPrefixes("brw_cat"), { default => undef}, + "getPrefixes: Undefined brw_cat prefix is undefined."); + is_deeply($config->getPrefixes("branch"), { default => undef}, + "getPrefixes: Undefined branch prefix is undefined."); + + # getDigitalRecipients (error & undef): + dies_ok( sub { $config->getDigitalRecipients("FOO") }, + "getDigitalRecipients: die if not correct type."); + is_deeply($config->getDigitalRecipients("brw_cat"), { default => undef}, + "getDigitalRecipients: Undefined brw_cat dig rec is undefined."); + is_deeply($config->getDigitalRecipients("branch"), { default => undef}, + "getDigitalRecipients: Undefined branch dig rec is undefined."); + + $config->{configuration} = Koha::Illrequest::Config::_load_configuration({ + backend_directory => '/tmp/', + prefix => 'DEFAULT-prefix', + digital_recipient => 'branch', + borrower_category => [ + { code => 'B', prefix => '2-prefix' }, + { code => 'C', digital_recipient => 'branch' } + ], + branch => [ + { code => '1', prefix => 'T-prefix' }, + { code => '2', digital_recipient => 'borrower' } + ] + }, 0 + ); + + # getPrefixes (values): + is_deeply($config->getPrefixes("brw_cat"), + { B => '2-prefix', default => 'DEFAULT-prefix' }, + "getPrefixes: return configuration brw_cat prefixes."); + is_deeply($config->getPrefixes("branch"), + { 1 => 'T-prefix', default => 'DEFAULT-prefix' }, + "getPrefixes: return configuration branch prefixes."); + + # getDigitalRecipients (values): + is_deeply($config->getDigitalRecipients("brw_cat"), + { C => 'branch', default => 'branch' }, + "getDigitalRecipients: return brw_cat digital_recipients."); + is_deeply($config->getDigitalRecipients("branch"), + { 2 => 'borrower', default => 'branch' }, + "getDigitalRecipients: return branch digital_recipients."); + + $schema->storage->txn_rollback; +}; + + +1; diff --git a/t/db_dependent/Illrequestattributes.t b/t/db_dependent/Illrequestattributes.t new file mode 100644 index 0000000000..ceb0474264 --- /dev/null +++ b/t/db_dependent/Illrequestattributes.t @@ -0,0 +1,63 @@ +#!/usr/bin/perl +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +use Modern::Perl; + +use File::Basename qw/basename/; +use Koha::Database; +use Koha::Patrons; +use t::lib::TestBuilder; + +use Test::More tests => 3; + +my $schema = Koha::Database->new->schema; +use_ok('Koha::Illrequestattribute'); +use_ok('Koha::Illrequestattributes'); + +subtest 'Basic object tests' => sub { + + plan tests => 5; + + $schema->storage->txn_begin; + + my $builder = t::lib::TestBuilder->new; + + my $illrqattr = $builder->build({ source => 'Illrequestattribute' }); + + my $illrqattr_obj = Koha::Illrequestattributes->find( + $illrqattr->{illrequest_id}, + $illrqattr->{type} + ); + isa_ok($illrqattr_obj, 'Koha::Illrequestattribute', + "Correctly create and load an illrequestattribute object."); + is($illrqattr_obj->illrequest_id, $illrqattr->{illrequest_id}, + "Illrequest_id getter works."); + is($illrqattr_obj->type, $illrqattr->{type}, + "Type getter works."); + is($illrqattr_obj->value, $illrqattr->{value}, + "Value getter works."); + + $illrqattr_obj->delete; + + is(Koha::Illrequestattributes->search->count, 0, + "No attributes found after delete."); + + $schema->storage->txn_rollback; +}; + +1; diff --git a/t/db_dependent/Illrequests.t b/t/db_dependent/Illrequests.t new file mode 100644 index 0000000000..34b9eda286 --- /dev/null +++ b/t/db_dependent/Illrequests.t @@ -0,0 +1,792 @@ +#!/usr/bin/perl +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +use Modern::Perl; + +use File::Basename qw/basename/; +use Koha::Database; +use Koha::Illrequestattributes; +use Koha::Illrequest::Config; +use Koha::Patrons; +use t::lib::Mocks; +use t::lib::TestBuilder; +use Test::MockObject; +use Test::Exception; + +use Test::More tests => 10; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; +use_ok('Koha::Illrequest'); +use_ok('Koha::Illrequests'); + +subtest 'Basic object tests' => sub { + + plan tests => 21; + + $schema->storage->txn_begin; + + my $illrq = $builder->build({ source => 'Illrequest' }); + my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id}); + + isa_ok($illrq_obj, 'Koha::Illrequest', + "Correctly create and load an illrequest object."); + isa_ok($illrq_obj->_config, 'Koha::Illrequest::Config', + "Created a config object as part of Illrequest creation."); + + is($illrq_obj->illrequest_id, $illrq->{illrequest_id}, + "Illrequest_id getter works."); + is($illrq_obj->borrowernumber, $illrq->{borrowernumber}, + "Borrowernumber getter works."); + is($illrq_obj->biblio_id, $illrq->{biblio_id}, + "Biblio_Id getter works."); + is($illrq_obj->branchcode, $illrq->{branchcode}, + "Branchcode getter works."); + is($illrq_obj->status, $illrq->{status}, + "Status getter works."); + is($illrq_obj->placed, $illrq->{placed}, + "Placed getter works."); + is($illrq_obj->replied, $illrq->{replied}, + "Replied getter works."); + is($illrq_obj->updated, $illrq->{updated}, + "Updated getter works."); + is($illrq_obj->completed, $illrq->{completed}, + "Completed getter works."); + is($illrq_obj->medium, $illrq->{medium}, + "Medium getter works."); + is($illrq_obj->accessurl, $illrq->{accessurl}, + "Accessurl getter works."); + is($illrq_obj->cost, $illrq->{cost}, + "Cost getter works."); + is($illrq_obj->notesopac, $illrq->{notesopac}, + "Notesopac getter works."); + is($illrq_obj->notesstaff, $illrq->{notesstaff}, + "Notesstaff getter works."); + is($illrq_obj->orderid, $illrq->{orderid}, + "Orderid getter works."); + is($illrq_obj->backend, $illrq->{backend}, + "Backend getter works."); + + isnt($illrq_obj->status, 'COMP', + "ILL is not currently marked complete."); + $illrq_obj->mark_completed; + is($illrq_obj->status, 'COMP', + "ILL is now marked complete."); + + $illrq_obj->delete; + + is(Koha::Illrequests->search->count, 0, + "No illrequest found after delete."); + + $schema->storage->txn_rollback; +}; + +subtest 'Working with related objects' => sub { + + plan tests => 5; + + $schema->storage->txn_begin; + + my $patron = $builder->build({ source => 'Borrower' }); + my $illrq = $builder->build({ + source => 'Illrequest', + value => { borrowernumber => $patron->{borrowernumber} } + }); + my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id}); + + isa_ok($illrq_obj->patron, 'Koha::Patron', + "OK accessing related patron."); + + $builder->build({ + source => 'Illrequestattribute', + value => { illrequest_id => $illrq_obj->illrequest_id, type => 'X' } + }); + $builder->build({ + source => 'Illrequestattribute', + value => { illrequest_id => $illrq_obj->illrequest_id, type => 'Y' } + }); + $builder->build({ + source => 'Illrequestattribute', + value => { illrequest_id => $illrq_obj->illrequest_id, type => 'Z' } + }); + + is($illrq_obj->illrequestattributes->count, Koha::Illrequestattributes->search->count, + "Fetching expected number of Illrequestattributes for our request."); + + my $illrq1 = $builder->build({ source => 'Illrequest' }); + $builder->build({ + source => 'Illrequestattribute', + value => { illrequest_id => $illrq1->{illrequest_id}, type => 'X' } + }); + + is($illrq_obj->illrequestattributes->count + 1, Koha::Illrequestattributes->search->count, + "Fetching expected number of Illrequestattributes for our request."); + + $illrq_obj->delete; + is(Koha::Illrequestattributes->search->count, 1, + "Correct number of illrequestattributes after delete."); + + isa_ok(Koha::Patrons->find($patron->{borrowernumber}), 'Koha::Patron', + "Borrower was not deleted after illrq delete."); + + $schema->storage->txn_rollback; +}; + +subtest 'Status Graph tests' => sub { + + plan tests => 4; + + $schema->storage->txn_begin; + + my $illrq = $builder->build({source => 'Illrequest'}); + my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id}); + + # _core_status_graph tests: it's just a constant, so here we just make + # sure it returns a hashref. + is(ref $illrq_obj->_core_status_graph, "HASH", + "_core_status_graph returns a hash."); + + # _status_graph_union: let's try different merge operations. + # Identity operation + is_deeply( + $illrq_obj->_status_graph_union($illrq_obj->_core_status_graph, {}), + $illrq_obj->_core_status_graph, + "core_status_graph + null = core_status_graph" + ); + + # Simple addition + is_deeply( + $illrq_obj->_status_graph_union({}, $illrq_obj->_core_status_graph), + $illrq_obj->_core_status_graph, + "null + core_status_graph = core_status_graph" + ); + + # Correct merge behaviour + is_deeply( + $illrq_obj->_status_graph_union({ + REQ => { + prev_actions => [ ], + id => 'REQ', + next_actions => [ ], + }, + }, { + QER => { + prev_actions => [ 'REQ' ], + id => 'QER', + next_actions => [ 'REQ' ], + }, + }), + { + REQ => { + prev_actions => [ 'QER' ], + id => 'REQ', + next_actions => [ 'QER' ], + }, + QER => { + prev_actions => [ 'REQ' ], + id => 'QER', + next_actions => [ 'REQ' ], + }, + }, + "REQ atom + linking QER = cyclical status graph" + ); + + $schema->storage->txn_rollback; +}; + +subtest 'Backend testing (mocks)' => sub { + + plan tests => 13; + + $schema->storage->txn_begin; + + # testing load_backend & available_backends requires that we have at least + # the Dummy plugin installed. load_backend & available_backends don't + # currently have tests as a result. + + my $backend = Test::MockObject->new; + $backend->set_isa('Koha::Illbackends::Mock'); + $backend->set_always('name', 'Mock'); + + my $patron = $builder->build({ source => 'Borrower' }); + my $illrq = $builder->build({ + source => 'Illrequest', + value => { borrowernumber => $patron->{borrowernumber} } + }); + my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id}); + + $illrq_obj->_backend($backend); + + isa_ok($illrq_obj->_backend, 'Koha::Illbackends::Mock', + "OK accessing mocked backend."); + + # _backend_capability tests: + # We need to test whether this optional feature of a mocked backend + # behaves as expected. + # 3 scenarios: feature not implemented, feature implemented, but requested + # capability is not provided by backend, & feature is implemented & + # capability exists. This method can be used to implement custom backend + # functionality, such as unmediated in the BLDSS backend (also see + # bugzilla 18837). + $backend->set_always('capabilities', undef); + is($illrq_obj->_backend_capability('Test'), 0, + "0 returned on Mock not implementing capabilities."); + + $backend->set_always('capabilities', 0); + is($illrq_obj->_backend_capability('Test'), 0, + "0 returned on Mock not implementing Test capability."); + + $backend->set_always('capabilities', sub { return 'bar'; } ); + is($illrq_obj->_backend_capability('Test'), 'bar', + "'bar' returned on Mock implementing Test capability."); + + # metadata test: we need to be sure that we return the arbitrary values + # from the backend. + $backend->mock( + 'metadata', + sub { + my ( $self, $rq ) = @_; + return { + ID => $rq->illrequest_id, + Title => $rq->patron->borrowernumber + } + } + ); + + is_deeply( + $illrq_obj->metadata, + { + ID => $illrq_obj->illrequest_id, + Title => $illrq_obj->patron->borrowernumber + }, + "Test metadata." + ); + + # capabilities: + + # No backend graph extension + $backend->set_always('status_graph', {}); + is_deeply($illrq_obj->capabilities('COMP'), + { + prev_actions => [ 'REQ' ], + id => 'COMP', + name => 'Completed', + ui_method_name => 'Mark completed', + method => 'mark_completed', + next_actions => [ ], + ui_method_icon => 'fa-check', + }, + "Dummy status graph for COMP."); + is($illrq_obj->capabilities('UNKNOWN'), undef, + "Dummy status graph for UNKNOWN."); + is_deeply($illrq_obj->capabilities(), + $illrq_obj->_core_status_graph, + "Dummy full status graph."); + # Simple backend graph extension + $backend->set_always('status_graph', + { + QER => { + prev_actions => [ 'REQ' ], + id => 'QER', + next_actions => [ 'REQ' ], + }, + }); + is_deeply($illrq_obj->capabilities('QER'), + { + prev_actions => [ 'REQ' ], + id => 'QER', + next_actions => [ 'REQ' ], + }, + "Simple status graph for QER."); + is($illrq_obj->capabilities('UNKNOWN'), undef, + "Simple status graph for UNKNOWN."); + is_deeply($illrq_obj->capabilities(), + $illrq_obj->_status_graph_union( + $illrq_obj->_core_status_graph, + { + QER => { + prev_actions => [ 'REQ' ], + id => 'QER', + next_actions => [ 'REQ' ], + }, + } + ), + "Simple full status graph."); + + # custom_capability: + + # No backend graph extension + $backend->set_always('status_graph', {}); + is($illrq_obj->custom_capability('unknown', {}), 0, + "Unknown candidate."); + + # Simple backend graph extension + $backend->set_always('status_graph', + { + ID => { + prev_actions => [ 'REQ' ], + id => 'ID', + method => 'identity', + next_actions => [ 'REQ' ], + }, + }); + $backend->mock('identity', + sub { my ( $self, $params ) = @_; return $params->{other}; }); + is($illrq_obj->custom_capability('identity', { test => 1 })->{test}, 1, + "Resolve identity custom_capability"); + + $schema->storage->txn_rollback; +}; + + +subtest 'Backend core methods' => sub { + + plan tests => 16; + + $schema->storage->txn_begin; + + # Build infrastructure + my $backend = Test::MockObject->new; + $backend->set_isa('Koha::Illbackends::Mock'); + $backend->set_always('name', 'Mock'); + + my $config = Test::MockObject->new; + $config->set_always('backend_dir', "/tmp"); + $config->set_always('getLimitRules', + { default => { count => 0, method => 'active' } }); + + my $illrq = $builder->build({source => 'Illrequest'}); + my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id}); + $illrq_obj->_config($config); + $illrq_obj->_backend($backend); + + # expandTemplate: + is_deeply($illrq_obj->expandTemplate({ test => 1, method => "bar" }), + { + test => 1, + method => "bar", + template => "/tmp/Mock/intra-includes/bar.inc", + opac_template => "/tmp/Mock/opac-includes/bar.inc", + }, + "ExpandTemplate"); + + # backend_create + # we are testing simple cases. + $backend->set_series('create', + { stage => 'bar', method => 'create' }, + { stage => 'commit', method => 'create' }, + { stage => 'commit', method => 'create' }); + # Test Copyright Clearance + t::lib::Mocks::mock_preference("ILLModuleCopyrightClearance", "Test Copyright Clearance."); + is_deeply($illrq_obj->backend_create({test => 1}), + { + error => 0, + status => '', + message => '', + method => 'create', + stage => 'copyrightclearance', + value => { + backend => "Mock" + } + }, + "Backend create: copyright clearance."); + t::lib::Mocks::mock_preference("ILLModuleCopyrightClearance", ""); + # Test non-commit + is_deeply($illrq_obj->backend_create({test => 1}), + { + stage => 'bar', method => 'create', + template => "/tmp/Mock/intra-includes/create.inc", + opac_template => "/tmp/Mock/opac-includes/create.inc", + }, + "Backend create: arbitrary stage."); + # Test commit + is_deeply($illrq_obj->backend_create({test => 1}), + { + stage => 'commit', method => 'create', permitted => 0, + template => "/tmp/Mock/intra-includes/create.inc", + opac_template => "/tmp/Mock/opac-includes/create.inc", + }, + "Backend create: arbitrary stage, not permitted."); + is($illrq_obj->status, "QUEUED", "Backend create: queued if restricted."); + $config->set_always('getLimitRules', {}); + $illrq_obj->status('NEW'); + is_deeply($illrq_obj->backend_create({test => 1}), + { + stage => 'commit', method => 'create', permitted => 1, + template => "/tmp/Mock/intra-includes/create.inc", + opac_template => "/tmp/Mock/opac-includes/create.inc", + }, + "Backend create: arbitrary stage, permitted."); + is($illrq_obj->status, "NEW", "Backend create: not-queued."); + + # backend_renew + $backend->set_series('renew', { stage => 'bar', method => 'renew' }); + is_deeply($illrq_obj->backend_renew({test => 1}), + { + stage => 'bar', method => 'renew', + template => "/tmp/Mock/intra-includes/renew.inc", + opac_template => "/tmp/Mock/opac-includes/renew.inc", + }, + "Backend renew: arbitrary stage."); + + # backend_cancel + $backend->set_series('cancel', { stage => 'bar', method => 'cancel' }); + is_deeply($illrq_obj->backend_cancel({test => 1}), + { + stage => 'bar', method => 'cancel', + template => "/tmp/Mock/intra-includes/cancel.inc", + opac_template => "/tmp/Mock/opac-includes/cancel.inc", + }, + "Backend cancel: arbitrary stage."); + + # backend_update_status + $backend->set_series('update_status', { stage => 'bar', method => 'update_status' }); + is_deeply($illrq_obj->backend_update_status({test => 1}), + { + stage => 'bar', method => 'update_status', + template => "/tmp/Mock/intra-includes/update_status.inc", + opac_template => "/tmp/Mock/opac-includes/update_status.inc", + }, + "Backend update_status: arbitrary stage."); + + # backend_confirm + $backend->set_series('confirm', { stage => 'bar', method => 'confirm' }); + is_deeply($illrq_obj->backend_confirm({test => 1}), + { + stage => 'bar', method => 'confirm', + template => "/tmp/Mock/intra-includes/confirm.inc", + opac_template => "/tmp/Mock/opac-includes/confirm.inc", + }, + "Backend confirm: arbitrary stage."); + + $config->set_always('partner_code', "ILLTSTLIB"); + $backend->set_always('metadata', { Test => "Foobar" }); + my $illbrn = $builder->build({ + source => 'Branch', + value => { branchemail => "", branchreplyto => "" } + }); + my $partner1 = $builder->build({ + source => 'Borrower', + value => { categorycode => "ILLTSTLIB" }, + }); + my $partner2 = $builder->build({ + source => 'Borrower', + value => { categorycode => "ILLTSTLIB" }, + }); + my $gen_conf = $illrq_obj->generic_confirm({ + current_branchcode => $illbrn->{branchcode} + }); + isnt(index($gen_conf->{value}->{draft}->{body}, $backend->metadata->{Test}), -1, + "Generic confirm: draft contains metadata." + ); + is($gen_conf->{value}->{partners}->next->borrowernumber, $partner1->{borrowernumber}, + "Generic cofnirm: partner 1 is correct." + ); + is($gen_conf->{value}->{partners}->next->borrowernumber, $partner2->{borrowernumber}, + "Generic confirm: partner 2 is correct." + ); + + dies_ok { $illrq_obj->generic_confirm({ + current_branchcode => $illbrn->{branchcode}, + stage => 'draft' + }) } + "Generic confirm: missing to dies OK."; + + dies_ok { $illrq_obj->generic_confirm({ + current_branchcode => $illbrn->{branchcode}, + partners => $partner1->{email}, + stage => 'draft' + }) } + "Generic confirm: missing from dies OK."; + + $schema->storage->txn_rollback; +}; + + +subtest 'Helpers' => sub { + + plan tests => 9; + + $schema->storage->txn_begin; + + # Build infrastructure + my $backend = Test::MockObject->new; + $backend->set_isa('Koha::Illbackends::Mock'); + $backend->set_always('name', 'Mock'); + + my $config = Test::MockObject->new; + $config->set_always('backend_dir', "/tmp"); + + my $patron = $builder->build({ + source => 'Borrower', + value => { categorycode => "A" } + }); + my $illrq = $builder->build({ + source => 'Illrequest', + value => { branchcode => "CPL", borrowernumber => $patron->{borrowernumber} } + }); + my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id}); + $illrq_obj->_config($config); + $illrq_obj->_backend($backend); + + # getPrefix + $config->set_series('getPrefixes', + { CPL => "TEST", TSL => "BAR", default => "DEFAULT" }, + { A => "ATEST", C => "CBAR", default => "DEFAULT" }); + is($illrq_obj->getPrefix({ brw_cat => "C", branch => "CPL" }), "CBAR", + "getPrefix: brw_cat"); + $config->set_series('getPrefixes', + { CPL => "TEST", TSL => "BAR", default => "DEFAULT" }, + { A => "ATEST", C => "CBAR", default => "DEFAULT" }); + is($illrq_obj->getPrefix({ brw_cat => "UNKNOWN", branch => "CPL" }), "TEST", + "getPrefix: branch"); + $config->set_series('getPrefixes', + { CPL => "TEST", TSL => "BAR", default => "DEFAULT" }, + { A => "ATEST", C => "CBAR", default => "DEFAULT" }); + is($illrq_obj->getPrefix({ brw_cat => "UNKNOWN", branch => "UNKNOWN" }), "DEFAULT", + "getPrefix: default"); + $config->set_always('getPrefixes', {}); + is($illrq_obj->getPrefix({ brw_cat => "UNKNOWN", branch => "UNKNOWN" }), "", + "getPrefix: the empty prefix"); + + # id_prefix + $config->set_series('getPrefixes', + { CPL => "TEST", TSL => "BAR", default => "DEFAULT" }, + { A => "ATEST", C => "CBAR", default => "DEFAULT" }); + is($illrq_obj->id_prefix, "ATEST-", "id_prefix: brw_cat"); + $config->set_series('getPrefixes', + { CPL => "TEST", TSL => "BAR", default => "DEFAULT" }, + { AB => "ATEST", CD => "CBAR", default => "DEFAULT" }); + is($illrq_obj->id_prefix, "TEST-", "id_prefix: branch"); + $config->set_series('getPrefixes', + { CPLT => "TEST", TSLT => "BAR", default => "DEFAULT" }, + { AB => "ATEST", CD => "CBAR", default => "DEFAULT" }); + is($illrq_obj->id_prefix, "DEFAULT-", "id_prefix: default"); + + # requires_moderation + $illrq_obj->status('NEW')->store; + is($illrq_obj->requires_moderation, undef, "requires_moderation: No."); + $illrq_obj->status('CANCREQ')->store; + is($illrq_obj->requires_moderation, 'CANCREQ', "requires_moderation: Yes."); + + $schema->storage->txn_rollback; +}; + + +subtest 'Censorship' => sub { + + plan tests => 2; + + $schema->storage->txn_begin; + + # Build infrastructure + my $backend = Test::MockObject->new; + $backend->set_isa('Koha::Illbackends::Mock'); + $backend->set_always('name', 'Mock'); + + my $config = Test::MockObject->new; + $config->set_always('backend_dir', "/tmp"); + + my $illrq = $builder->build({source => 'Illrequest'}); + my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id}); + $illrq_obj->_config($config); + $illrq_obj->_backend($backend); + + $config->set_always('censorship', { censor_notes_staff => 1, censor_reply_date => 0 }); + + my $censor_out = $illrq_obj->_censor({ foo => 'bar', baz => 564 }); + is_deeply($censor_out, { foo => 'bar', baz => 564, display_reply_date => 1 }, + "_censor: not OPAC, reply_date = 1"); + + $censor_out = $illrq_obj->_censor({ foo => 'bar', baz => 564, opac => 1 }); + is_deeply($censor_out, { + foo => 'bar', baz => 564, censor_notes_staff => 1, + display_reply_date => 1, opac => 1 + }, "_censor: notes_staff = 0, reply_date = 0"); + + $schema->storage->txn_rollback; +}; + +subtest 'Checking Limits' => sub { + + plan tests => 30; + + $schema->storage->txn_begin; + + # Build infrastructure + my $backend = Test::MockObject->new; + $backend->set_isa('Koha::Illbackends::Mock'); + $backend->set_always('name', 'Mock'); + + my $config = Test::MockObject->new; + $config->set_always('backend_dir', "/tmp"); + + my $illrq = $builder->build({source => 'Illrequest'}); + my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id}); + $illrq_obj->_config($config); + $illrq_obj->_backend($backend); + + # getLimits + $config->set_series('getLimitRules', + { CPL => { count => 1, method => 'test' } }, + { default => { count => 0, method => 'active' } }); + is_deeply($illrq_obj->getLimits({ type => 'branch', value => "CPL" }), + { count => 1, method => 'test' }, + "getLimits: by value."); + is_deeply($illrq_obj->getLimits({ type => 'branch' }), + { count => 0, method => 'active' }, + "getLimits: by default."); + is_deeply($illrq_obj->getLimits({ type => 'branch', value => "CPL" }), + { count => -1, method => 'active' }, + "getLimits: by hard-coded."); + + #_limit_counter + is($illrq_obj->_limit_counter('annual', { branchcode => $illrq_obj->branchcode }), + 1, "_limit_counter: Initial branch annual count."); + is($illrq_obj->_limit_counter('active', { branchcode => $illrq_obj->branchcode }), + 1, "_limit_counter: Initial branch active count."); + is($illrq_obj->_limit_counter('annual', { borrowernumber => $illrq_obj->borrowernumber }), + 1, "_limit_counter: Initial patron annual count."); + is($illrq_obj->_limit_counter('active', { borrowernumber => $illrq_obj->borrowernumber }), + 1, "_limit_counter: Initial patron active count."); + $builder->build({ + source => 'Illrequest', + value => { + branchcode => $illrq_obj->branchcode, + borrowernumber => $illrq_obj->borrowernumber, + } + }); + is($illrq_obj->_limit_counter('annual', { branchcode => $illrq_obj->branchcode }), + 2, "_limit_counter: Add a qualifying request for branch annual count."); + is($illrq_obj->_limit_counter('active', { branchcode => $illrq_obj->branchcode }), + 2, "_limit_counter: Add a qualifying request for branch active count."); + is($illrq_obj->_limit_counter('annual', { borrowernumber => $illrq_obj->borrowernumber }), + 2, "_limit_counter: Add a qualifying request for patron annual count."); + is($illrq_obj->_limit_counter('active', { borrowernumber => $illrq_obj->borrowernumber }), + 2, "_limit_counter: Add a qualifying request for patron active count."); + $builder->build({ + source => 'Illrequest', + value => { + branchcode => $illrq_obj->branchcode, + borrowernumber => $illrq_obj->borrowernumber, + placed => "2005-05-31", + } + }); + is($illrq_obj->_limit_counter('annual', { branchcode => $illrq_obj->branchcode }), + 2, "_limit_counter: Add an out-of-date branch request."); + is($illrq_obj->_limit_counter('active', { branchcode => $illrq_obj->branchcode }), + 3, "_limit_counter: Add a qualifying request for branch active count."); + is($illrq_obj->_limit_counter('annual', { borrowernumber => $illrq_obj->borrowernumber }), + 2, "_limit_counter: Add an out-of-date patron request."); + is($illrq_obj->_limit_counter('active', { borrowernumber => $illrq_obj->borrowernumber }), + 3, "_limit_counter: Add a qualifying request for patron active count."); + $builder->build({ + source => 'Illrequest', + value => { + branchcode => $illrq_obj->branchcode, + borrowernumber => $illrq_obj->borrowernumber, + status => "COMP", + } + }); + is($illrq_obj->_limit_counter('annual', { branchcode => $illrq_obj->branchcode }), + 3, "_limit_counter: Add a qualifying request for branch annual count."); + is($illrq_obj->_limit_counter('active', { branchcode => $illrq_obj->branchcode }), + 3, "_limit_counter: Add a completed request for branch active count."); + is($illrq_obj->_limit_counter('annual', { borrowernumber => $illrq_obj->borrowernumber }), + 3, "_limit_counter: Add a qualifying request for patron annual count."); + is($illrq_obj->_limit_counter('active', { borrowernumber => $illrq_obj->borrowernumber }), + 3, "_limit_counter: Add a completed request for patron active count."); + + # check_limits: + + # We've tested _limit_counter, so all we need to test here is whether the + # current counts of 3 for each work as they should against different + # configuration declarations. + + # No limits + $config->set_always('getLimitRules', undef); + is($illrq_obj->check_limits({patron => $illrq_obj->patron, + librarycode => $illrq_obj->branchcode}), + 1, "check_limits: no configuration => no limits."); + + # Branch tests + $config->set_always('getLimitRules', + { $illrq_obj->branchcode => { count => 1, method => 'active' } }); + is($illrq_obj->check_limits({patron => $illrq_obj->patron, + librarycode => $illrq_obj->branchcode}), + 0, "check_limits: branch active limit exceeded."); + $config->set_always('getLimitRules', + { $illrq_obj->branchcode => { count => 1, method => 'annual' } }); + is($illrq_obj->check_limits({patron => $illrq_obj->patron, + librarycode => $illrq_obj->branchcode}), + 0, "check_limits: branch annual limit exceeded."); + $config->set_always('getLimitRules', + { $illrq_obj->branchcode => { count => 4, method => 'active' } }); + is($illrq_obj->check_limits({patron => $illrq_obj->patron, + librarycode => $illrq_obj->branchcode}), + 1, "check_limits: branch active limit OK."); + $config->set_always('getLimitRules', + { $illrq_obj->branchcode => { count => 4, method => 'annual' } }); + is($illrq_obj->check_limits({patron => $illrq_obj->patron, + librarycode => $illrq_obj->branchcode}), + 1, "check_limits: branch annual limit OK."); + + # Patron tests + $config->set_always('getLimitRules', + { $illrq_obj->patron->categorycode => { count => 1, method => 'active' } }); + is($illrq_obj->check_limits({patron => $illrq_obj->patron, + librarycode => $illrq_obj->branchcode}), + 0, "check_limits: patron category active limit exceeded."); + $config->set_always('getLimitRules', + { $illrq_obj->patron->categorycode => { count => 1, method => 'annual' } }); + is($illrq_obj->check_limits({patron => $illrq_obj->patron, + librarycode => $illrq_obj->branchcode}), + 0, "check_limits: patron category annual limit exceeded."); + $config->set_always('getLimitRules', + { $illrq_obj->patron->categorycode => { count => 4, method => 'active' } }); + is($illrq_obj->check_limits({patron => $illrq_obj->patron, + librarycode => $illrq_obj->branchcode}), + 1, "check_limits: patron category active limit OK."); + $config->set_always('getLimitRules', + { $illrq_obj->patron->categorycode => { count => 4, method => 'annual' } }); + is($illrq_obj->check_limits({patron => $illrq_obj->patron, + librarycode => $illrq_obj->branchcode}), + 1, "check_limits: patron category annual limit OK."); + + # One rule cancels the other + $config->set_series('getLimitRules', + # Branch rules allow request + { $illrq_obj->branchcode => { count => 4, method => 'active' } }, + # Patron rule forbids it + { $illrq_obj->patron->categorycode => { count => 1, method => 'annual' } }); + is($illrq_obj->check_limits({patron => $illrq_obj->patron, + librarycode => $illrq_obj->branchcode}), + 0, "check_limits: patron category veto overrides branch OK."); + $config->set_series('getLimitRules', + # Branch rules allow request + { $illrq_obj->branchcode => { count => 1, method => 'active' } }, + # Patron rule forbids it + { $illrq_obj->patron->categorycode => { count => 4, method => 'annual' } }); + is($illrq_obj->check_limits({patron => $illrq_obj->patron, + librarycode => $illrq_obj->branchcode}), + 0, "check_limits: branch veto overrides patron category OK."); + + $schema->storage->txn_rollback; +}; + +1; -- 2.14.2