Bug 7614: Consider transfer limits in Koha::Template::Plugin::Branches
[koha.git] / t / db_dependent / OAI / Server.t
blobf924994850c80b472adb727a01fa1b25b4ce358a
1 #!/usr/bin/perl
3 # Copyright Tamil s.a.r.l. 2016
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
20 use Modern::Perl;
21 use Test::MockTime qw/set_fixed_time restore_time/;
23 use Test::More tests => 30;
24 use DateTime;
25 use Test::MockModule;
26 use Test::Warn;
27 use XML::Simple;
28 use YAML;
30 use t::lib::Mocks;
32 use C4::Biblio;
33 use C4::Context;
35 use Koha::Biblio::Metadatas;
36 use Koha::Database;
37 use Koha::DateUtils;
39 BEGIN {
40 use_ok('Koha::OAI::Server::DeletedRecord');
41 use_ok('Koha::OAI::Server::Description');
42 use_ok('Koha::OAI::Server::GetRecord');
43 use_ok('Koha::OAI::Server::Identify');
44 use_ok('Koha::OAI::Server::ListBase');
45 use_ok('Koha::OAI::Server::ListIdentifiers');
46 use_ok('Koha::OAI::Server::ListMetadataFormats');
47 use_ok('Koha::OAI::Server::ListRecords');
48 use_ok('Koha::OAI::Server::ListSets');
49 use_ok('Koha::OAI::Server::Record');
50 use_ok('Koha::OAI::Server::Repository');
51 use_ok('Koha::OAI::Server::ResumptionToken');
54 use constant NUMBER_OF_MARC_RECORDS => 10;
56 # Mocked CGI module in order to be able to send CGI parameters to OAI Server
57 my %param;
58 my $module = Test::MockModule->new('CGI');
59 $module->mock('Vars', sub { %param; });
61 my $schema = Koha::Database->schema;
62 $schema->storage->txn_begin;
63 my $dbh = C4::Context->dbh;
65 $dbh->do("SET time_zone='+00:00'");
66 $dbh->do('DELETE FROM issues');
67 $dbh->do('DELETE FROM biblio');
68 $dbh->do('DELETE FROM deletedbiblio');
69 $dbh->do('DELETE FROM deletedbiblioitems');
70 $dbh->do('DELETE FROM deleteditems');
71 $dbh->do('DELETE FROM oai_sets');
73 set_fixed_time(CORE::time());
75 my $base_datetime = DateTime->now();
76 my $date_added = $base_datetime->ymd . ' ' .$base_datetime->hms . 'Z';
77 my $date_to = substr($date_added, 0, 10) . 'T23:59:59Z';
78 my (@header, @marcxml, @oaidc);
79 my $sth = $dbh->prepare('UPDATE biblioitems SET timestamp=? WHERE biblionumber=?');
80 my $sth2 = $dbh->prepare('UPDATE biblio_metadata SET timestamp=? WHERE biblionumber=?');
82 # Add biblio records
83 foreach my $index ( 0 .. NUMBER_OF_MARC_RECORDS - 1 ) {
84 my $record = MARC::Record->new();
85 if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
86 $record->append_fields( MARC::Field->new('101', '', '', 'a' => "lng" ) );
87 $record->append_fields( MARC::Field->new('200', '', '', 'a' => "Title $index" ) );
88 } else {
89 $record->append_fields( MARC::Field->new('008', ' lng' ) );
90 $record->append_fields( MARC::Field->new('245', '', '', 'a' => "Title $index" ) );
92 my ($biblionumber) = AddBiblio($record, '');
93 my $timestamp = $base_datetime->ymd . ' ' .$base_datetime->hms;
94 $sth->execute($timestamp,$biblionumber);
95 $sth2->execute($timestamp,$biblionumber);
96 $timestamp .= 'Z';
97 $timestamp =~ s/ /T/;
98 $record = GetMarcBiblio({ biblionumber => $biblionumber });
99 $record = XMLin($record->as_xml_record);
100 push @header, { datestamp => $timestamp, identifier => "TEST:$biblionumber" };
101 my $dc = {
102 'dc:title' => "Title $index",
103 'dc:language' => "lng",
104 'dc:type' => {},
105 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
106 'xmlns:oai_dc' => 'http://www.openarchives.org/OAI/2.0/oai_dc/',
107 'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
108 'xsi:schemaLocation' => 'http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd',
110 if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
111 $dc->{'dc:identifier'} = $biblionumber;
113 push @oaidc, {
114 header => $header[$index],
115 metadata => {
116 'oai_dc:dc' => $dc,
119 push @marcxml, {
120 header => $header[$index],
121 metadata => {
122 record => $record,
127 my $syspref = {
128 'LibraryName' => 'My Library',
129 'OAI::PMH' => 1,
130 'OAI-PMH:archiveID' => 'TEST',
131 'OAI-PMH:ConfFile' => '',
132 'OAI-PMH:MaxCount' => 3,
133 'OAI-PMH:DeletedRecord' => 'persistent',
135 while ( my ($name, $value) = each %$syspref ) {
136 t::lib::Mocks::mock_preference( $name => $value );
139 sub test_query {
140 my ($test, $param, $expected) = @_;
142 %param = %$param;
143 my %full_expected = (
144 %$expected,
146 request => 'http://localhost',
147 xmlns => 'http://www.openarchives.org/OAI/2.0/',
148 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
149 'xsi:schemaLocation' => 'http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd',
153 my $response;
155 my $stdout;
156 local *STDOUT;
157 open STDOUT, '>', \$stdout;
158 Koha::OAI::Server::Repository->new();
159 $response = XMLin($stdout);
162 delete $response->{responseDate};
163 unless (is_deeply($response, \%full_expected, $test)) {
164 diag
165 "PARAM:" . Dump($param) .
166 "EXPECTED:" . Dump(\%full_expected) .
167 "RESPONSE:" . Dump($response);
171 test_query('ListMetadataFormats', {verb => 'ListMetadataFormats'}, {
172 ListMetadataFormats => {
173 metadataFormat => [
175 metadataNamespace => 'http://www.openarchives.org/OAI/2.0/oai_dc/',
176 metadataPrefix=> 'oai_dc',
177 schema => 'http://www.openarchives.org/OAI/2.0/oai_dc.xsd',
180 metadataNamespace => 'http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim',
181 metadataPrefix => 'marc21',
182 schema => 'http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd',
185 metadataNamespace => 'http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim',
186 metadataPrefix => 'marcxml',
187 schema => 'http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd',
193 test_query('ListIdentifiers without metadataPrefix', {verb => 'ListIdentifiers'}, {
194 error => {
195 code => 'badArgument',
196 content => "Required argument 'metadataPrefix' was undefined",
200 test_query('ListIdentifiers', {verb => 'ListIdentifiers', metadataPrefix => 'marcxml'}, {
201 ListIdentifiers => {
202 header => [ @header[0..2] ],
203 resumptionToken => {
204 content => "marcxml/3/1970-01-01T00:00:00Z/$date_to//0/0",
205 cursor => 3,
210 test_query('ListIdentifiers', {verb => 'ListIdentifiers', metadataPrefix => 'marcxml'}, {
211 ListIdentifiers => {
212 header => [ @header[0..2] ],
213 resumptionToken => {
214 content => "marcxml/3/1970-01-01T00:00:00Z/$date_to//0/0",
215 cursor => 3,
220 test_query(
221 'ListIdentifiers with resumptionToken 1',
222 { verb => 'ListIdentifiers', resumptionToken => "marcxml/3/1970-01-01T00:00:00Z/$date_to//0/0" },
224 ListIdentifiers => {
225 header => [ @header[3..5] ],
226 resumptionToken => {
227 content => "marcxml/6/1970-01-01T00:00:00Z/$date_to//0/0",
228 cursor => 6,
234 test_query(
235 'ListIdentifiers with resumptionToken 2',
236 { verb => 'ListIdentifiers', resumptionToken => "marcxml/6/1970-01-01T00:00:00Z/$date_to//0/0" },
238 ListIdentifiers => {
239 header => [ @header[6..8] ],
240 resumptionToken => {
241 content => "marcxml/9/1970-01-01T00:00:00Z/$date_to//0/0",
242 cursor => 9,
248 test_query(
249 'ListIdentifiers with resumptionToken 3, response without resumption',
250 { verb => 'ListIdentifiers', resumptionToken => "marcxml/9/1970-01-01T00:00:00Z/$date_to//0/0" },
252 ListIdentifiers => {
253 header => $header[9],
258 test_query('ListRecords marcxml without metadataPrefix', {verb => 'ListRecords'}, {
259 error => {
260 code => 'badArgument',
261 content => "Required argument 'metadataPrefix' was undefined",
265 test_query('ListRecords marcxml', {verb => 'ListRecords', metadataPrefix => 'marcxml'}, {
266 ListRecords => {
267 record => [ @marcxml[0..2] ],
268 resumptionToken => {
269 content => "marcxml/3/1970-01-01T00:00:00Z/$date_to//0/0",
270 cursor => 3,
275 test_query(
276 'ListRecords marcxml with resumptionToken 1',
277 { verb => 'ListRecords', resumptionToken => "marcxml/3/1970-01-01T00:00:00Z/$date_to//0/0" },
278 { ListRecords => {
279 record => [ @marcxml[3..5] ],
280 resumptionToken => {
281 content => "marcxml/6/1970-01-01T00:00:00Z/$date_to//0/0",
282 cursor => 6,
287 test_query(
288 'ListRecords marcxml with resumptionToken 2',
289 { verb => 'ListRecords', resumptionToken => "marcxml/6/1970-01-01T00:00:00Z/$date_to//0/0" },
290 { ListRecords => {
291 record => [ @marcxml[6..8] ],
292 resumptionToken => {
293 content => "marcxml/9/1970-01-01T00:00:00Z/$date_to//0/0",
294 cursor => 9,
299 # Last record, so no resumption token
300 test_query(
301 'ListRecords marcxml with resumptionToken 3, response without resumption',
302 { verb => 'ListRecords', resumptionToken => "marcxml/9/1970-01-01T00:00:00Z/$date_to//0/0" },
303 { ListRecords => {
304 record => $marcxml[9],
308 test_query('ListRecords oai_dc', {verb => 'ListRecords', metadataPrefix => 'oai_dc'}, {
309 ListRecords => {
310 record => [ @oaidc[0..2] ],
311 resumptionToken => {
312 content => "oai_dc/3/1970-01-01T00:00:00Z/$date_to//0/0",
313 cursor => 3,
318 test_query(
319 'ListRecords oai_dc with resumptionToken 1',
320 { verb => 'ListRecords', resumptionToken => "oai_dc/3/1970-01-01T00:00:00Z/$date_to//0/0" },
321 { ListRecords => {
322 record => [ @oaidc[3..5] ],
323 resumptionToken => {
324 content => "oai_dc/6/1970-01-01T00:00:00Z/$date_to//0/0",
325 cursor => 6,
330 test_query(
331 'ListRecords oai_dc with resumptionToken 2',
332 { verb => 'ListRecords', resumptionToken => "oai_dc/6/1970-01-01T00:00:00Z/$date_to//0/0" },
333 { ListRecords => {
334 record => [ @oaidc[6..8] ],
335 resumptionToken => {
336 content => "oai_dc/9/1970-01-01T00:00:00Z/$date_to//0/0",
337 cursor => 9,
342 # Last record, so no resumption token
343 test_query(
344 'ListRecords oai_dc with resumptionToken 3, response without resumption',
345 { verb => 'ListRecords', resumptionToken => "oai_dc/9/1970-01-01T00:00:00Z/$date_to//0/0" },
346 { ListRecords => {
347 record => $oaidc[9],
351 restore_time();
353 subtest 'Bug 19725: OAI-PMH ListRecords and ListIdentifiers should use biblio_metadata.timestamp' => sub {
354 plan tests => 1;
356 # Wait 1 second to be sure no timestamp will be equal to $from defined below
357 sleep 1;
359 # Modify record to trigger auto update of timestamp
360 (my $biblionumber = $marcxml[0]->{header}->{identifier}) =~ s/^.*:(.*)/$1/;
361 my $record = GetMarcBiblio({biblionumber => $biblionumber});
362 $record->append_fields(MARC::Field->new(999, '', '', z => '_'));
363 ModBiblio( $record, $biblionumber );
364 my $from_dt = dt_from_string(
365 Koha::Biblio::Metadatas->find({ biblionumber => $biblionumber, format => 'marcxml', marcflavour => 'MARC21' })->timestamp
367 my $from = $from_dt->ymd . 'T' . $from_dt->hms . 'Z';
368 $oaidc[0]->{header}->{datestamp} = $from;
370 test_query(
371 'ListRecords oai_dc with parameter from',
372 { verb => 'ListRecords', metadataPrefix => 'oai_dc', from => $from },
373 { ListRecords => {
374 record => $oaidc[0],
379 subtest 'Bug 20665: OAI-PMH Provider should reset the MySQL connection time zone' => sub {
380 plan tests => 2;
382 # Set time zone to SYSTEM so that it can be checked later
383 $dbh->do("SET time_zone='SYSTEM'");
386 test_query('ListIdentifiers without metadataPrefix', {verb => 'ListIdentifiers'}, {
387 error => {
388 code => 'badArgument',
389 content => "Required argument 'metadataPrefix' was undefined",
393 my $sth = C4::Context->dbh->prepare('SELECT @@session.time_zone');
394 $sth->execute();
395 my ( $tz ) = $sth->fetchrow();
397 ok ( $tz eq 'SYSTEM', 'MySQL connection time zone is SYSTEM' );
401 $schema->storage->txn_rollback;