Bugzilla – Attachment 106461 Details for
Bug 24544
Add a script for inserting persistent identifiers to MARC records
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 24544: Introduce Koha::PID::Controller with unit test
Bug-24544-Introduce-KohaPIDController-with-unit-te.patch (text/plain), 27.58 KB, created by
Marcel de Rooy
on 2020-07-02 06:45:41 UTC
(
hide
)
Description:
Bug 24544: Introduce Koha::PID::Controller with unit test
Filename:
MIME Type:
Creator:
Marcel de Rooy
Created:
2020-07-02 06:45:41 UTC
Size:
27.58 KB
patch
obsolete
>From 0b31cf40f3b19472eb77b7f275722497d1614fd8 Mon Sep 17 00:00:00 2001 >From: Marcel de Rooy <m.de.rooy@rijksmuseum.nl> >Date: Thu, 30 Jan 2020 13:51:57 +0000 >Subject: [PATCH] Bug 24544: Introduce Koha::PID::Controller with unit test >Content-Type: text/plain; charset=utf-8 > >This new module will facilitate inserting/updating PIDs in authority, >biblio and item records. > >Test plan: >Run t/db_dependent/Koha/PID/Controller.t > >Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl> >--- > Koha/PID/Controller.pm | 401 +++++++++++++++++++++++++++++++++++ > t/db_dependent/Koha/PID/Controller.t | 270 +++++++++++++++++++++++ > 2 files changed, 671 insertions(+) > create mode 100644 Koha/PID/Controller.pm > create mode 100644 t/db_dependent/Koha/PID/Controller.t > >diff --git a/Koha/PID/Controller.pm b/Koha/PID/Controller.pm >new file mode 100644 >index 0000000000..b1ded3a205 >--- /dev/null >+++ b/Koha/PID/Controller.pm >@@ -0,0 +1,401 @@ >+package Koha::PID::Controller; >+ >+# This file is part of Koha. >+# >+# Copyright (C) 2020 Rijksmuseum >+# >+# 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 3 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, see <http://www.gnu.org/licenses>. >+ >+=head1 NAME >+ >+Koha::PID::Controller -- Facilitate handling of persistent identifiers >+ >+=cut >+ >+use Modern::Perl; >+#use Data::Dumper qw/Dumper/; >+ >+use C4::AuthoritiesMarc qw//; >+use C4::Biblio qw//; >+use C4::Context; >+use Koha::Authorities; >+use Koha::Biblios; >+use Koha::Exceptions; >+use Koha::Items; >+use Koha::Plugins; >+ >+=head1 METHODS >+ >+=head2 new >+ >+ my $ctrl = Koha::PID::Controller->new({ domain => _optional_domain_ }); >+ >+ Simple constructor; blesses any passed hash reference. >+ The object parses and caches the pref PID_Field during its lifetime. >+ It also keeps PID_Domain or the overriding parameter to extract PIDs in the get method. >+ >+=cut >+ >+sub new { >+ my ( $class, $params ) = @_; >+ my $self = ref($params) eq 'HASH' ? $params : {}; >+ >+ $self->{_field} = _parse_field(); >+ $self->{_domain} = $params->{domain} || C4::Context->preference('PID_Domain') || q/http/; >+ >+ return bless $self, $class; >+} >+ >+sub _parse_field { # Return hash for field/subfield per auth, biblio or item >+ my $pref = C4::Context->preference('PID_Field'); >+ # form is: auth:999$x,biblio:999$x,item (subfield $x optional) >+ >+ my $hash = {}; >+ foreach my $cat ( split /,/, $pref ) { >+ if( $cat eq 'item' ) { >+ $hash->{item} = 1; # items are handled differently >+ next; >+ } >+ next if $cat !~ /^(auth|biblio)[:=]/; >+ my @temp = split /[:=]/, $cat, 2; >+ next if @temp<2 || !$temp[1]; >+ if( $temp[1] =~ /(\d{3})\$(.)$/ ) { >+ $hash->{$temp[0]}->{tag} = $1; >+ $hash->{$temp[0]}->{subfield} = $2; >+ } elsif( $temp[1] =~ /(\d{3})/ ) { >+ $hash->{$temp[0]}->{tag} = $1; >+ $hash->{$temp[0]}->{subfield} = 'a' if $1 ge '010'; >+ } >+ } >+ return $hash; >+} >+ >+=head2 get >+ >+ my $pid = $ctrl->get({ >+ category => $category, >+ kohaIdentifier => $kohaIdentifier, >+ [ object => $object ], >+ }); >+ >+ Get persistent URI from record for category/kohaIdentifier. >+ Depends on PID_Field and PID_Domain (see new method). >+ Optionally pass corresponding Koha object/MARC record. >+ >+ Can be controlled with plugin method pid_get_hook. >+ Note: a plugin that returns false, makes get return undef. >+ >+ Returns URI or undef. >+ >+=cut >+ >+sub get { >+ my ( $self, $params ) = @_; >+ my $category = $params->{category}; >+ my $kohaIdentifier = $params->{kohaIdentifier}; >+ my $object = $params->{object}; >+ >+ return if !exists $self->{_field}->{$category}; >+ >+ my $record = $self->_get_record($category, $kohaIdentifier, $object); >+ return if !$self->_get_hook($category, $record); # optional plugin control >+ >+ my @fields; >+ if( $category eq 'item') { >+ # check domain and return the first == last inserted one >+ @fields = grep { /\Q$self->{_domain}\E/ } split ' | ', $record->uri//''; >+ return _first_uri(@fields); >+ } >+ >+ my $tag = $self->{_field}->{$category}->{tag}; >+ my $sf = $self->{_field}->{$category}->{subfield}; >+ if( !$sf ) { # control field, might be UNIMARC; no check on domain >+ return _first_uri( $record->field($tag)->data ); >+ } >+ >+ # Regular MARC21 walk-through for auth or biblio >+ @fields = map { $_->subfield($sf) && $_->subfield($sf) =~ /\Q$self->{_domain}\E/ ? $_->subfield($sf) : () } $record->field($tag); >+ return _first_uri(@fields); >+} >+ >+sub _get_record { >+ my ( $self, $category, $kohaIdentifier, $object ) = @_; >+ my $record; >+ if( $category eq 'biblio' ) { >+ $object = Koha::Biblios->find($kohaIdentifier) unless $object; >+ $record = $object->metadata->record; >+ } elsif( $category eq 'item' ) { >+ $record = $object // Koha::Items->find($kohaIdentifier); >+ } else { # assume authority >+ $object = Koha::Authorities->find( $kohaIdentifier ) unless $object; >+ $record = MARC::Record->new_from_xml($object->marcxml, 'UTF-8', C4::Context->preference("marcflavour") eq "UNIMARC" ? "UNIMARCAUTH" : "MARC21" ) >+ if $object; >+ } >+ Koha::Exceptions::ObjectNotFound->throw( error => "No record found for $category:$kohaIdentifier\n" ) if !$record; >+ return $record; >+} >+ >+sub _get_hook { # these plugins may modify $record to control results, or return false >+ my ($self, $category, $record) = @_; >+ my $rv; >+ foreach my $plugin ( Koha::Plugins->new->GetPlugins({ method => 'pid_get_hook' }) ) { >+ $rv = $plugin->pid_get_hook({ record => $record, category => $category }); >+ return if !$rv; >+ } >+ return 1; >+} >+ >+sub _first_uri { >+ my ($first, @rest) = @_; >+ return if !defined $first; >+ $first =~ s/^.*http/http/; # could be spaces or perhaps orgcode in 035, not expecting two http occurrences >+ return $first; >+} >+ >+=head2 create >+ >+ my $uri = $ctrl->create({ category => $category, kohaIdentifier => $kohaIdentifier }); >+ >+ Creates a new persistent identifier URI. >+ This is plugin controlled. It needs a pid_create_hook method. The first returned true value is used. >+ Preferably, this plugin should be the interface to an external service. >+ Category, kohaIdentifier and domain (from object creation) are passed to the plugin. >+ Note that authtypecode (like PERSO_NAME etc.) is passed as category for authority records. >+ Does not (directly) depend on PID_Field and PID_Domain. >+ >+ Returns { success =>0|1, [ uri => ... ], [ info => 'additional' ] } >+ >+=cut >+ >+sub create { >+ my ( $self, $params ) = @_; >+ my $category = $params->{category}; >+ my $kohaIdentifier = $params->{kohaIdentifier}; >+ >+ my $authtypecode; >+ if( $category eq 'auth' ) { >+ my $rec = Koha::Authorities->find( $kohaIdentifier ); >+ $authtypecode = $rec->authtypecode if $rec; >+ } >+ >+ # Call plugin >+ my @plugins = Koha::Plugins->new->GetPlugins({ method => 'pid_create_hook' }); >+ return { success => 0, info => 'NO_PLUGIN' } if !@plugins; >+ my $domain = $self->{_domain} eq 'http' ? q{} : $self->{_domain}; >+ my $rv; >+ foreach my $plugin ( @plugins ) { >+ $rv = eval { $plugins[0]->pid_create_hook({ category => $authtypecode // $category, identifier => $kohaIdentifier, domain => $domain }) }; >+ last if $rv; # first true value >+ } >+ if( !$rv ) { >+ return { success => 0, info => $@ // q{} }; >+ } else { >+ return { success => 1, uri => $rv }; >+ } >+} >+ >+=head2 insert >+ >+ $ctrl->insert({ >+ pid => $pid, >+ category => $category, >+ kohaIdentifier => $kohaIdentifier, >+ [ object => $object ], >+ [ do_not_save => 1 ], >+ }); >+ >+ Insert $pid into the record referenced by $category and $kohaIdentifier. >+ Optionally pass corresponding Koha object/MARC record. >+ Depends on PID_Field. >+ >+ Behavior can be controlled with plugin hook pid_insert_hook. >+ The plugin is called with $pid, record, $category and inserted flag. >+ The inserted flag tells if a new field was inserted (no exact match found). >+ >+ The do_not_save flag may be used for optimization. Use it with care. >+ Returns an errcode if the $pid already exists. >+ >+ Returns { success => 1|0, [record => $marc | $item ], [ errcode => X ] } >+ >+=cut >+ >+sub insert { >+ my ( $self, $params ) = @_; >+ my $pid = $params->{pid}; >+ my $category = $params->{category}; >+ my $kohaIdentifier = $params->{kohaIdentifier}; >+ my $object = $params->{object}; >+ >+ return { success => 0, errcode => 'INV_CAT' } if !exists $self->{_field}->{$category}; >+ my $record = $self->_get_record($category, $kohaIdentifier, $object); >+ >+ # Add new field >+ my $insert; >+ if( $category eq 'item') { >+ $insert = $self->_update_item_field( $record, $pid ); >+ } else { >+ $insert = $self->_update_marc_record( $record, $category, $pid ); >+ } >+ >+ # Call plugin >+ my (@plugins, $rv); >+ @plugins = Koha::Plugins->new->GetPlugins({ method => 'pid_insert_hook' }); >+ foreach my $plugin ( @plugins ) { >+ $rv = $plugin->pid_insert_hook({ pid => $pid, record => $record, category => $category, inserted => $insert }); >+ return { success => 0, errcode => 'HOOK' } if !$rv; >+ } >+ return { success => 0, errcode => 'EXIST' } if !@plugins && !$insert; >+ $self->_default_insert_hook({ pid => $pid, record => $record, category => $category }) if !@plugins; >+ >+ # Save >+ $category = Koha::Authorities->find( $kohaIdentifier )->authtypecode if $category eq 'auth'; # should exist >+ $self->_save_record( $category, $kohaIdentifier, $record ) unless $params->{do_not_save}; >+ return { success => 1, record => $record }; >+} >+ >+sub _update_item_field { >+ my ($self, $record, $pid ) = @_; >+ >+ my $value = $record->uri; >+ if( !$value ) { >+ $value = $pid; >+ } elsif( $value =~ /(^|\| )$pid($| \|)/ ) { # exists >+ return; >+ } else { # insert in front >+ $value= "$pid | $value"; >+ } >+ $record->uri( $value ); >+ return 1; >+} >+ >+sub _update_marc_record { >+ my ( $self, $record, $category, $pid ) = @_; >+ my $tag = $self->{_field}->{$category}->{tag}; >+ my $sf = $self->{_field}->{$category}->{subfield}; >+ >+ if(!$sf) { # control field >+ if( $record->field($tag) ) { >+ return if $record->field($tag)->data eq $pid; >+ $record->field($tag)->update( $pid ); # overwrite >+ } else { >+ $record->insert_fields_ordered( MARC::Field->new($tag, $pid) ); >+ } >+ } else { >+ # Adds a new field unless we find an exact match >+ return if grep { $_->subfield($sf) && $_->subfield($sf) eq $pid } $record->field($tag); >+ my $field = MARC::Field->new( $tag, '', '', $sf => $pid ); >+ $record->insert_fields_ordered($field); >+ } >+ return 1; >+} >+ >+sub _default_insert_hook { >+# If there are no hooks, this sub is used to update 024 when you specified it in PID_Field >+# Note: If you want to disable this behavior, add a hook returning true >+ my ($self, $params) = @_; # pid, record, category >+ my $category = $params->{category}; >+ my $record = $params->{record}; >+ if( $category eq 'item' ) { # skip >+ } elsif( $self->{_field}->{$category}->{tag} eq '024' ) { >+ $record->field('024')->update( ind1 => '7', 2 => 'uri' ); # affects only first inserted 024 >+ } >+} >+ >+sub _save_record { >+ my ( $self, $category, $kohaIdentifier, $record ) = @_; >+ >+ if( $category eq 'item' ) { >+ $record->store; # previously calling ModItem >+ } elsif( $category eq 'biblio' ) { >+ C4::Biblio::ModBiblio($record, $kohaIdentifier, C4::Biblio::GetFrameworkCode($kohaIdentifier)); >+ } else { >+ C4::AuthoritiesMarc::ModAuthority( $kohaIdentifier, $record, $category ); >+ } >+} >+ >+1; >+__END__ >+ >+=head1 SYNOPSIS >+ >+use Koha::PID::Controller; >+my $ctrl = Koha::PID::Controller->new; >+ >+my $pid = $ctrl->get({ category => $category, kohaIdentifier => $kohaIdentifier }); >+ >+my $newpid = $ctrl->create({ category => $category, kohaIdentifier => $kohaIdentifier }); >+if( !$ctrl->insert({ pid => $newpid, category => $category, kohaIdentifier => $kohaIdentifier })->{success} ) { >+ # tell me >+} >+ >+=head1 DESCRIPTION >+ >+This controller allows you to maintain persistent identifiers in MARC records >+of bibliographic and authority records for MARC21 and UNIMARC, and in items. >+ >+Operation is controlled by preferences PID_Field and PID_Domain. PID_Field allows >+you to specify which categories (auth, biblio, item) have PIDs, and where to store >+them. PID_Domain is used as a base URL for finding PIDs. >+ >+The module has three main methods: get, create and insert. Get extracts a PID from >+a record. Create generates a new PID. And insert saves a PID into a record. All three >+methods have a plugin hook to control the operation: pid_get_hook, pid_create_hook and >+pid_insert_hook. The get and insert method do not depend on a plugin hook, but the create >+method does not provide results without pid_create_hook. >+ >+Preference PID_Field allows you to store the PIDs for biblio and authority records >+anywhere in the MARC record. But MARC21 field 024 or UNIMARC field 003 would >+probably be your best choice. (If you choose 024, a default insert hook >+updates indicator1 and adds $2 for you. Only in absence of other insert hooks.) >+ >+=head1 ADDITIONAL COMMENTS >+ >+=head2 pid_get_hook >+ >+This hook receives a parameter hash with record and category. It should return true >+or false. >+ >+Before the get method looks at the record, it runs the get hooks. If one returns false, >+get returns undef. Furthermore, the hook receives the MARC record or item object. >+So it allows you to also control results by changing field values (which are not saved >+in the method, but be careful when you also use the object parameter). >+ >+Get performs a contains match on PID_Domain. If this is too simple to fit your needs, >+your get hook could reorder or remove fields so that get returns what you want. Note >+that this may involve choosing an intelligent value for PID_Domain. >+ >+=head2 pid_create_hook >+ >+This hook receives a parameter hash with category, identifier and domain. It should >+return a URI or false. The first true value is used. >+ >+The create hook is meant to be the interface to your PID generator. Which should normally >+be independent of the source system (Koha). You could also use it as your PID generator, >+although purists won't like that. >+ >+=head2 pid_insert_hook >+ >+This hook receives a parameter hash with pid, record, category and inserted. It should >+return true or false. (Inserted flag: see below.) A false value makes insert return an >+error condition while not saving the change. >+ >+The hook is called after the insert method adds a new field. But it did not add a field >+when an exact match was found. The inserted flag tells the plugin about that. The hook >+allows you to customize field changes. >+ >+=head1 AUTHOR >+ >+Marcel de Rooy, Rijksmuseum >+ >+=cut >diff --git a/t/db_dependent/Koha/PID/Controller.t b/t/db_dependent/Koha/PID/Controller.t >new file mode 100644 >index 0000000000..ae1112ff8c >--- /dev/null >+++ b/t/db_dependent/Koha/PID/Controller.t >@@ -0,0 +1,270 @@ >+#!/usr/bin/perl >+ >+# This file is part of Koha. >+# >+# Copyright (C) 2020 Rijksmuseum >+# >+# 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 3 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, see <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+#use Data::Dumper qw/Dumper/; >+use MARC::Record; >+use Test::More tests => 4; >+use Test::MockModule; >+use Test::MockObject; >+use Test::Warn; >+ >+use t::lib::Mocks; >+use t::lib::TestBuilder; >+ >+use C4::AuthoritiesMarc qw//; >+use C4::Biblio qw//; >+use C4::Context; >+use C4::Items; >+use Koha::Database; >+use Koha::PID::Controller; >+ >+our $schema = Koha::Database->new->schema; >+our $builder = t::lib::TestBuilder->new; >+ >+our @plugins; >+my $plugin_module = Test::MockModule->new( 'Koha::Plugins' ); >+$plugin_module->mock( 'GetPlugins', sub { return @plugins; }); >+ >+$schema->storage->txn_begin; >+ >+subtest 'Test get method (biblio)' => sub { >+ plan tests => 6; >+ >+ my $plugin = Test::MockObject->new; >+ >+ my $record = MARC::Record->new; >+ $record->append_fields( >+ MARC::Field->new( '003', 'http://unimarc.fr/U-003' ), >+ MARC::Field->new( '024', '', '', 1 => 'http://donotgohere.com/M24a', q => 'qual_a' ), >+ MARC::Field->new( '024', '', '', 1 => 'http://bestpersistentid.nl/M24b' ), >+ MARC::Field->new( '024', '', '', 1 => 'http://bestpersistentid.nl/M24c', q => 'qual_c' ), >+ MARC::Field->new( '035', '', '', a => '(RMA) http://mysite01.org/M35a' ), # deliberate spaces >+ MARC::Field->new( '035', '', '', a => '(RMAxx)http://mysite02.org/M35b' ), >+ MARC::Field->new( '035', '', '', a => '(RMAxx)http://bestpersistentid.nl/M35c' ), >+ MARC::Field->new( '035', '', '', a => '(RMAx) http://mysite03.org/M35d' ), >+ ); >+ my ($biblionumber) = C4::Biblio::AddBiblio( $record, q{} ); >+ >+ t::lib::Mocks::mock_preference('PID_Field', 'biblio:003'); >+ t::lib::Mocks::mock_preference('PID_Domain', 'http://bestpersistentid.nl'); >+ my $ctrl = Koha::PID::Controller->new; >+ # UNIMARC 003, no domain control >+ like( $ctrl->get({ category => 'biblio', kohaIdentifier => $biblionumber }), qr/^http.*U-003$/, 'Test get for UNIMARC biblio' ); >+ >+ t::lib::Mocks::mock_preference('PID_Field', 'biblio:024$1'); >+ $ctrl = Koha::PID::Controller->new; >+ # MARC21 024 $1, domain controlled >+ like( $ctrl->get({ category => 'biblio', kohaIdentifier => $biblionumber }), qr/^http.*M24b$/, 'Test get b for MARC21 biblio (024)' ); >+ >+ $plugin->mock( 'pid_get_hook', \&get_hook_24 ); >+ push @plugins, $plugin; >+ t::lib::Mocks::mock_preference('PID_Domain', q{}); >+ $ctrl = Koha::PID::Controller->new; >+ # MARC21 024 $1, no domain check, plugin hook (qualifier) >+ like( $ctrl->get({ category => 'biblio', kohaIdentifier => $biblionumber }), qr/^http.*M24c$/, 'Test get c for MARC21 biblio (024)' ); >+ pop @plugins; >+ >+ t::lib::Mocks::mock_preference('PID_Field', 'biblio:035'); # NOTE: we omit subfield >+ t::lib::Mocks::mock_preference('PID_Domain', 'http://bestpersistentid.nl'); >+ $ctrl = Koha::PID::Controller->new; >+ # MARC21 035 $a, domain controlled >+ like( $ctrl->get({ category => 'biblio', kohaIdentifier => $biblionumber }), qr/^http.*M35c$/, 'Test get c for MARC21 biblio (035)' ); >+ >+ $ctrl = Koha::PID::Controller->new({ domain => 'site' }); >+ # MARC21 035 $a, incomplete domain check >+ like( $ctrl->get({ category => 'biblio', kohaIdentifier => $biblionumber }), qr/^http.*M35a$/, 'Test get a for MARC21 biblio (035)' ); >+ >+ $plugin->mock( 'pid_get_hook', \&get_hook_35 ); >+ push @plugins, $plugin; >+ t::lib::Mocks::mock_preference('MARCOrgCode', 'RMAx'); >+ t::lib::Mocks::mock_preference('PID_Domain', q{}); >+ $ctrl = Koha::PID::Controller->new; >+ # MARC21 035 $a, no domain check, plugin hook (orgcode) >+ like( $ctrl->get({ category => 'biblio', kohaIdentifier => $biblionumber }), qr/^http.*M35d$/, 'Test get d for MARC21 biblio (035)' ); >+ pop @plugins; >+}; >+ >+sub get_hook_24 { # Mimics plugin that makes get return 024 with condition on $q >+ my ($self, $params) = @_; >+ my $record = $params->{record}; >+ my $qual = 'qual_c'; >+ foreach my $fld ( $record->field('024') ) { >+ if( !$fld->subfield('q') || $fld->subfield('q') !~ /^\Q$qual\E/ ) { >+ $record->delete_fields( $fld ); >+ } >+ } >+ return 1; >+} >+ >+sub get_hook_35 { # Mimics plugin that makes get return 035 with orgcode >+ my ($self, $params) = @_; >+ my $record = $params->{record}; >+ my $orgcode = C4::Context->preference('MARCOrgCode'); >+ foreach my $fld ( $record->field('035') ) { >+ if( !$fld->subfield('a') || $fld->subfield('a') !~ /^\(\Q$orgcode\E\)/ ) { >+ $record->delete_fields( $fld ); >+ } >+ } >+ return 1; >+} >+ >+subtest 'Test get method (item)' => sub { >+ plan tests => 4; >+ >+ # Test item with object >+ t::lib::Mocks::mock_preference('PID_Field', 'item'); >+ t::lib::Mocks::mock_preference('PID_Domain', 'my'); # do not use this value normally >+ my $ctrl = Koha::PID::Controller->new; >+ my $item = $builder->build_object({ class => 'Koha::Items', value => { uri => 'uri01 | my02 | uri03 | http://site04.org' } }); >+ is( $ctrl->get({ category => 'item', object => $item }), 'my02', 'Test get my02 for item' ); >+ # Test fallback to http >+ t::lib::Mocks::mock_preference('PID_Domain', q{}); >+ $ctrl = Koha::PID::Controller->new; >+ like( $ctrl->get({ category => 'item', kohaIdentifier => $item->itemnumber }), qr/04\.org$/, 'Test get http item' ); >+ # Item hook >+ my $plugin = Test::MockObject->new; >+ $plugin->mock( 'pid_get_hook', \&get_hook_item ); >+ push @plugins, $plugin; >+ $ctrl->get({ category => 'item', object => $item }); >+ is( $item->itemnotes, 'Reached', 'Item hook executed' ); >+ pop @plugins; >+ # Test clearing PID_Field >+ t::lib::Mocks::mock_preference('PID_Field', q{}); >+ $ctrl = Koha::PID::Controller->new; >+ is( $ctrl->get({ category => 'item', kohaIdentifier => $item->itemnumber }), undef, 'Test no item category' ); >+}; >+ >+sub get_hook_item { # Simple hack to test execution >+ my ($self, $params) = @_; >+ my $record = $params->{record}; # Koha::Item >+ $record->itemnotes('Reached'); >+ return 1; >+} >+ >+subtest 'Test create' => sub { >+ plan tests => 4; >+ >+ my $plugin = Test::MockObject->new; >+ $plugin->mock( 'pid_create_hook', \&create_hook ); >+ push @plugins, $plugin; >+ my $ctrl = Koha::PID::Controller->new({ domain => 'https://id.rijksmuseum.nl' }); >+ is( $ctrl->create({ category => 'biblio', kohaIdentifier => 100000 })->{uri}, 'https://id.rijksmuseum.nl/biblio/100000', "Create biblio pid" ); >+ # Category is not checked >+ is( $ctrl->create({ category => 'unchecked', kohaIdentifier => 999 })->{uri}, 'https://id.rijksmuseum.nl/unchecked/999', "Create unchecked pid" ); >+ # Two plugins, 'whatever' comes first >+ unshift @plugins, Test::MockObject->new->mock( 'pid_create_hook', sub { 'whatever' } ); >+ my $rv = $ctrl->create({ category => 'auth', kohaIdentifier => 1234 }); >+ is( $rv->{uri}, 'whatever', "Result of first plugin returning true value" ); >+ # No plugins >+ @plugins = (); >+ is( $ctrl->create({ category => 'item', kohaIdentifier => 654321 })->{success}, 0, "Test without plugin" ); >+}; >+ >+sub create_hook { # Super trivial return >+ my ($self, $params) = @_; >+ return $params->{domain}. '/'. $params->{category}. '/'. $params->{identifier}; >+} >+ >+subtest 'Test insert' => sub { >+ plan tests => 19; >+ >+ t::lib::Mocks::mock_preference('PID_Field', 'biblio:024$1,item'); >+ my $ctrl = Koha::PID::Controller->new; >+ >+ # category undefined >+ is( $ctrl->insert({ pid => '1', category => 'auth', kohaIdentifier => 1 })->{errcode}, 'INV_CAT', 'Undefined category' ); >+ >+ # hook >+ my $plugin = Test::MockObject->new; >+ $plugin->mock( 'pid_insert_hook', \&insert_hook ); >+ push @plugins, $plugin; >+ my $item = $builder->build_object({ class => 'Koha::Items', value => { uri => 'A | B' } }); >+ $ctrl->insert({ pid => '1', category => 'item', kohaIdentifier => $item->itemnumber }); # 1 | A | B >+ is( @plugins, 0, 'Hook got executed' ); >+ # item >+ $item->discard_changes; >+ is( $item->uri, '1 | A | B', 'Check result of item insert' ); >+ # reinsert the same value >+ is( $ctrl->insert({ pid => '1', category => 'item', kohaIdentifier => $item->itemnumber })->{errcode}, 'EXIST', 'Check reinsert' ); >+ # Test do_not_save >+ my $result = $ctrl->insert({ pid => '2', category => 'item', kohaIdentifier => $item->itemnumber, do_not_save => 1 }); >+ like( $result->{record}->uri, qr/^2/, 'New uri in response' ); >+ $item->discard_changes; >+ is( $item->uri, '1 | A | B', 'But not saved as expected' ); >+ >+ # marc record changes (biblio or auth) >+ my $biblio = $builder->build_sample_biblio; >+ my $record; >+ $result = $ctrl->insert({ pid => '123', category => 'biblio', kohaIdentifier => $biblio->biblionumber }); >+ $record = C4::Biblio::GetMarcBiblio({ biblionumber => $biblio->biblionumber }); >+ is( $record->subfield('024', '1'), '123', 'Check biblio pid 123' ); >+ is( $record->field('024')->indicator(1), '7', 'Check indicator1 from default hook' ); >+ is( $record->subfield('024', '2'), 'uri', 'Check $2 from default hook' ); >+ # reinsert (without hook) >+ $result = $ctrl->insert({ pid => '123', category => 'biblio', kohaIdentifier => $biblio->biblionumber }); >+ is( $result->{errcode}, 'EXIST', 'Check reinsert 123' ); >+ # empty hook >+ $plugin->mock('after_biblio_action', sub {} ); # prevent warn >+ $plugin->mock('pid_insert_hook', sub { 1; } ); >+ push @plugins, $plugin; >+ $result = $ctrl->insert({ pid => '456', category => 'biblio', kohaIdentifier => $biblio->biblionumber }); >+ $record = C4::Biblio::GetMarcBiblio({ biblionumber => $biblio->biblionumber }); >+ is( $record->subfield('024', '1'), '456', 'Check biblio pid 456' ); >+ is( $record->field('024')->indicator(1), q{ }, 'Check if indicator1 blank' ); >+ is( $record->subfield('024', '2'), undef, 'Check if $2 empty' ); >+ # reinsert (with hook) >+ $result = $ctrl->insert({ pid => '123', category => 'biblio', kohaIdentifier => $biblio->biblionumber }); >+ is( $result->{success}, 1, 'Reinsert with hook returns success' ); # since the hook 'fixes everything' >+ my @fields = $result->{record}->field('024'); >+ is( @fields, 2, 'Still expecting to find two 024s' ); >+ # hook returns false >+ my $plugin2 = Test::MockObject->new; >+ $plugin2->mock('pid_insert_hook', sub {} ); >+ push @plugins, $plugin2; >+ $result = $ctrl->insert({ pid => '567', category => 'biblio', kohaIdentifier => $biblio->biblionumber }); >+ is( $result->{errcode}, 'HOOK', 'Hook returned false' ); >+ @plugins = (); >+ >+ # PERSO_NAME authority >+ t::lib::Mocks::mock_preference('PID_Field', 'auth:024'); >+ $ctrl = Koha::PID::Controller->new; >+ $record = MARC::Record->new; >+ my $authid = C4::AuthoritiesMarc::AddAuthority( $record, undef, 'PERSO_NAME' ); >+ $result = $ctrl->insert({ pid => '234', category => 'auth', kohaIdentifier => $authid }); >+ $record = $result->{record}; >+ is( $record->subfield('024', 'a'), '234', 'Check auth pid 234' ); >+ # control field >+ t::lib::Mocks::mock_preference('PID_Field', 'auth:003'); >+ $ctrl = Koha::PID::Controller->new; >+ $result = $ctrl->insert({ pid => '345', category => 'auth', kohaIdentifier => $authid }); >+ $record = $result->{record}; >+ is( $record->field('003')->data, '345', 'Check auth pid 345' ); >+ # reinsert >+ $result = $ctrl->insert({ pid => '345', category => 'auth', kohaIdentifier => $authid }); >+ is( $result->{errcode}, 'EXIST', 'Check reinsert 345' ); >+}; >+ >+sub insert_hook { >+ my ($self, $params) = @_; >+ pop @plugins; # self destructive ;) >+ return 1; >+} >+ >+$schema->storage->txn_rollback; >-- >2.11.0
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 24544
:
106460
|
106461
|
106462
|
106463
|
106464