Bug 22246: Fix indexing of large fields with Elasticsearch
[koha.git] / t / Koha / SearchEngine / Elasticsearch.t
index 323a3b0..1fe3ad1 100644 (file)
@@ -25,8 +25,10 @@ use t::lib::Mocks;
 use Test::MockModule;
 
 use MARC::Record;
+use Try::Tiny;
 
 use Koha::SearchEngine::Elasticsearch;
+use Koha::SearchEngine::Elasticsearch::Search;
 
 subtest '_read_configuration() tests' => sub {
 
@@ -115,11 +117,29 @@ subtest 'get_elasticsearch_mappings() tests' => sub {
 
 subtest 'Koha::SearchEngine::Elasticsearch::marc_records_to_documents () tests' => sub {
 
-    plan tests => 32;
+    plan tests => 49;
 
     t::lib::Mocks::mock_preference('marcflavour', 'MARC21');
 
     my @mappings = (
+        {
+            name => 'control_number',
+            type => 'string',
+            facet => 0,
+            suggestible => 0,
+            sort => undef,
+            marc_type => 'marc21',
+            marc_field => '001',
+        },
+        {
+            name => 'isbn',
+            type => 'isbn',
+            facet => 0,
+            suggestible => 0,
+            sort => 0,
+            marc_type => 'marc21',
+            marc_field => '020a',
+        },
         {
             name => 'author',
             type => 'string',
@@ -165,6 +185,15 @@ subtest 'Koha::SearchEngine::Elasticsearch::marc_records_to_documents () tests'
             marc_type => 'marc21',
             marc_field => '220',
         },
+        {
+            name => 'title_wildcard',
+            type => 'string',
+            facet => 0,
+            suggestible => 0,
+            sort => undef,
+            marc_type => 'marc21',
+            marc_field => '245',
+        },
         {
             name => 'sum_item_price',
             type => 'sum',
@@ -183,6 +212,15 @@ subtest 'Koha::SearchEngine::Elasticsearch::marc_records_to_documents () tests'
             marc_type => 'marc21',
             marc_field => '9520',
         },
+        {
+            name => 'local_classification',
+            type => 'string',
+            facet => 0,
+            suggestible => 0,
+            sort => 1,
+            marc_type => 'marc21',
+            marc_field => '952o',
+        },
         {
             name => 'type_of_record',
             type => 'string',
@@ -220,19 +258,26 @@ subtest 'Koha::SearchEngine::Elasticsearch::marc_records_to_documents () tests'
         }
     });
 
-    my $see = Koha::SearchEngine::Elasticsearch->new({ index => 'biblios' });
+    my $see = Koha::SearchEngine::Elasticsearch::Search->new({ index => $Koha::SearchEngine::Elasticsearch::BIBLIOS_INDEX });
+
+    my $callno = 'ABC123';
+    my $callno2 = 'ABC456';
+    my $long_callno = '1234567890' x 30;
 
     my $marc_record_1 = MARC::Record->new();
     $marc_record_1->leader('     cam  22      a 4500');
     $marc_record_1->append_fields(
+        MARC::Field->new('001', '123'),
+        MARC::Field->new('020', '', '', a => '1-56619-909-3'),
         MARC::Field->new('100', '', '', a => 'Author 1'),
         MARC::Field->new('110', '', '', a => 'Corp Author'),
         MARC::Field->new('210', '', '', a => 'Title 1'),
         MARC::Field->new('245', '', '', a => 'Title:', b => 'first record'),
         MARC::Field->new('999', '', '', c => '1234567'),
         # '  ' for testing trimming of white space in boolean value callback:
-        MARC::Field->new('952', '', '', 0 => '  ', g => '123.30'),
-        MARC::Field->new('952', '', '', 0 => 0, g => '127.20'),
+        MARC::Field->new('952', '', '', 0 => '  ', g => '123.30', o => $callno),
+        MARC::Field->new('952', '', '', 0 => 0, g => '127.20', o => $callno2),
+        MARC::Field->new('952', '', '', 0 => 1, g => '0.00', o => $long_callno),
     );
     my $marc_record_2 = MARC::Record->new();
     $marc_record_2->leader('     cam  22      a 4500');
@@ -241,7 +286,7 @@ subtest 'Koha::SearchEngine::Elasticsearch::marc_records_to_documents () tests'
         # MARC::Field->new('210', '', '', a => 'Title 2'),
         # MARC::Field->new('245', '', '', a => 'Title: second record'),
         MARC::Field->new('999', '', '', c => '1234568'),
-        MARC::Field->new('952', '', '', 0 => 1, g => 'string where should be numeric'),
+        MARC::Field->new('952', '', '', 0 => 1, g => 'string where should be numeric', o => $long_callno),
     );
     my $records = [$marc_record_1, $marc_record_2];
 
@@ -250,19 +295,23 @@ subtest 'Koha::SearchEngine::Elasticsearch::marc_records_to_documents () tests'
     my $docs = $see->marc_records_to_documents($records);
 
     # First record:
-
     is(scalar @{$docs}, 2, 'Two records converted to documents');
 
     is($docs->[0][0], '1234567', 'First document biblionumber should be set as first element in document touple');
 
+    is_deeply($docs->[0][1]->{control_number}, ['123'], 'First record control number should be set correctly');
+
     is(scalar @{$docs->[0][1]->{author}}, 2, 'First document author field should contain two values');
     is_deeply($docs->[0][1]->{author}, ['Author 1', 'Corp Author'], 'First document author field should be set correctly');
 
-    is(scalar @{$docs->[0][1]->{author__sort}}, 2, 'First document author__sort field should have two values');
-    is_deeply($docs->[0][1]->{author__sort}, ['Author 1', 'Corp Author'], 'First document author__sort field should be set correctly');
+    is(scalar @{$docs->[0][1]->{author__sort}}, 1, 'First document author__sort field should have a single value');
+    is_deeply($docs->[0][1]->{author__sort}, ['Author 1 Corp Author'], 'First document author__sort field should be set correctly');
 
-    is(scalar @{$docs->[0][1]->{title__sort}}, 3, 'First document title__sort field should have three values');
-    is_deeply($docs->[0][1]->{title__sort}, ['Title:', 'first record', 'Title: first record'], 'First document title__sort field should be set correctly');
+    is(scalar @{$docs->[0][1]->{title__sort}}, 1, 'First document title__sort field should have a single');
+    is_deeply($docs->[0][1]->{title__sort}, ['Title: first record Title: first record'], 'First document title__sort field should be set correctly');
+
+    is(scalar @{$docs->[0][1]->{title_wildcard}}, 2, 'First document title_wildcard field should have two values');
+    is_deeply($docs->[0][1]->{title_wildcard}, ['Title:', 'first record'], 'First document title_wildcard field should be set correctly');
 
     is(scalar @{$docs->[0][1]->{author__suggestion}}, 2, 'First document author__suggestion field should contain two values');
     is_deeply(
@@ -301,7 +350,7 @@ subtest 'Koha::SearchEngine::Elasticsearch::marc_records_to_documents () tests'
     is(scalar @{$docs->[0][1]->{items_withdrawn_status}}, 2, 'First document items_withdrawn_status field should have two values');
     is_deeply(
         $docs->[0][1]->{items_withdrawn_status},
-        ['false', 'false'],
+        ['false', 'true'],
         'First document items_withdrawn_status field should be set correctly'
     );
 
@@ -312,11 +361,14 @@ subtest 'Koha::SearchEngine::Elasticsearch::marc_records_to_documents () tests'
     );
 
     ok(defined $docs->[0][1]->{marc_data}, 'First document marc_data field should be set');
-
     ok(defined $docs->[0][1]->{marc_format}, 'First document marc_format field should be set');
-
     is($docs->[0][1]->{marc_format}, 'base64ISO2709', 'First document marc_format should be set correctly');
 
+    my $decoded_marc_record = $see->decode_record_from_result($docs->[0][1]);
+
+    ok($decoded_marc_record->isa('MARC::Record'), "base64ISO2709 record successfully decoded from result");
+    is($decoded_marc_record->as_usmarc(), $marc_record_1->as_usmarc(), "Decoded base64ISO2709 record has same data as original record");
+
     is(scalar @{$docs->[0][1]->{type_of_record}}, 1, 'First document type_of_record field should have one value');
     is_deeply(
         $docs->[0][1]->{type_of_record},
@@ -331,6 +383,15 @@ subtest 'Koha::SearchEngine::Elasticsearch::marc_records_to_documents () tests'
         'First document type_of_record_and_bib_level field should be set correctly'
     );
 
+    is(scalar @{$docs->[0][1]->{isbn}}, 4, 'First document isbn field should contain four values');
+    is_deeply($docs->[0][1]->{isbn}, ['978-1-56619-909-4', '9781566199094', '1-56619-909-3', '1566199093'], 'First document isbn field should be set correctly');
+
+    is_deeply(
+        $docs->[0][1]->{'local_classification'},
+        [$callno, $callno2, $long_callno],
+        'First document local_classification field should be set correctly'
+    );
+
     # Second record:
 
     is(scalar @{$docs->[1][1]->{author}}, 1, 'Second document author field should contain one value');
@@ -349,6 +410,12 @@ subtest 'Koha::SearchEngine::Elasticsearch::marc_records_to_documents () tests'
         'Second document sum_item_price field should be set correctly'
     );
 
+    is_deeply(
+        $docs->[1][1]->{local_classification__sort},
+        [substr($long_callno, 0, 255)],
+        'Second document local_classification__sort field should be set correctly'
+    );
+
     # Mappings marc_type:
 
     ok(!(defined $docs->[0][1]->{unimarc_title}), "No mapping when marc_type doesn't match marc flavour");
@@ -376,4 +443,51 @@ subtest 'Koha::SearchEngine::Elasticsearch::marc_records_to_documents () tests'
 
     is($docs->[0][1]->{marc_format}, 'MARCXML', 'For record exceeding max record size marc_format should be set correctly');
 
+    $decoded_marc_record = $see->decode_record_from_result($docs->[0][1]);
+
+    ok($decoded_marc_record->isa('MARC::Record'), "MARCXML record successfully decoded from result");
+    is($decoded_marc_record->as_xml_record(), $large_marc_record->as_xml_record(), "Decoded MARCXML record has same data as original record");
+
+    push @mappings, {
+        name => 'title',
+        type => 'string',
+        facet => 0,
+        suggestible => 1,
+        sort => 1,
+        marc_type => 'marc21',
+        marc_field => '245((ab)ab',
+    };
+
+    my $exception = try {
+        $see->marc_records_to_documents($records);
+    }
+    catch {
+        return $_;
+    };
+
+    ok(defined $exception, "Exception has been thrown when processing mapping with unmatched opening parenthesis");
+    ok($exception->isa("Koha::Exceptions::Elasticsearch::MARCFieldExprParseError"), "Exception is of correct class");
+    ok($exception->message =~ /Unmatched opening parenthesis/, "Exception has the correct message");
+
+    pop @mappings;
+    push @mappings, {
+        name => 'title',
+        type => 'string',
+        facet => 0,
+        suggestible => 1,
+        sort => 1,
+        marc_type => 'marc21',
+        marc_field => '245(ab))ab',
+    };
+
+    $exception = try {
+        $see->marc_records_to_documents($records);
+    }
+    catch {
+        return $_;
+    };
+
+    ok(defined $exception, "Exception has been thrown when processing mapping with unmatched closing parenthesis");
+    ok($exception->isa("Koha::Exceptions::Elasticsearch::MARCFieldExprParseError"), "Exception is of correct class");
+    ok($exception->message =~ /Unmatched closing parenthesis/, "Exception has the correct message");
 };