From b4900001788401970c6920efb4e82d636fc40749 Mon Sep 17 00:00:00 2001
From: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Date: Fri, 29 Oct 2021 11:15:48 +0200
Subject: [PATCH] Bug 29368: Correctly mock Zebra index from tests

This is just reusing what is done in Search.t (and that is correct).
But search_utf8.t and remove_from_cart.t are wrong as we want to use the
UI (and we cannot mock the zebra index, ie. koha-conf, from tests for
plack).

This still needs some work but improve a bit the existing code and make
tests pass (hopefully!)
---
 t/db_dependent/Search.t                    | 119 +++++++++------------
 t/db_dependent/selenium/remove_from_cart.t |   7 +-
 t/db_dependent/www/search_utf8.t           |  21 ++--
 t/lib/Mocks/Zebra.pm                       |  79 ++++++++++++--
 4 files changed, 132 insertions(+), 94 deletions(-)

diff --git a/t/db_dependent/Search.t b/t/db_dependent/Search.t
index 8ccb0d81804..6d84995b938 100755
--- a/t/db_dependent/Search.t
+++ b/t/db_dependent/Search.t
@@ -30,6 +30,7 @@ use Test::More tests => 3;
 use Test::MockModule;
 use Test::Warn;
 use t::lib::Mocks;
+use t::lib::Mocks::Zebra;
 
 use Koha::Caches;
 
@@ -41,56 +42,9 @@ use File::Find;
 use File::Temp qw/ tempdir /;
 use File::Path;
 
-our $child;
-our $datadir;
-
-sub index_sample_records_and_launch_zebra {
-    my ($datadir, $marc_type) = @_;
-
-    my $sourcedir = dirname(__FILE__) . "/data";
-    unlink("$datadir/zebra.log");
-    if (-f "$sourcedir/${marc_type}/zebraexport/biblio/exported_records") {
-        my $zebra_bib_cfg = 'zebra-biblios-dom.cfg';
-        system("zebraidx -c $datadir/etc/koha/zebradb/$zebra_bib_cfg  -v none,fatal -g iso2709 -d biblios init");
-        system("zebraidx -c $datadir/etc/koha/zebradb/$zebra_bib_cfg  -v none,fatal -g iso2709 -d biblios update $sourcedir/${marc_type}/zebraexport/biblio");
-        system("zebraidx -c $datadir/etc/koha/zebradb/$zebra_bib_cfg  -v none,fatal -g iso2709 -d biblios commit");
-    }
-    # ... and add large bib records, if present
-    if (-f "$sourcedir/${marc_type}/zebraexport/large_biblio/exported_records.xml") {
-        my $zebra_bib_cfg = 'zebra-biblios-dom.cfg';
-        system("zebraidx -c $datadir/etc/koha/zebradb/$zebra_bib_cfg  -v none,fatal -g marcxml -d biblios update $sourcedir/${marc_type}/zebraexport/large_biblio");
-        system("zebraidx -c $datadir/etc/koha/zebradb/$zebra_bib_cfg  -v none,fatal -g marcxml -d biblios commit");
-    }
-    if (-f "$sourcedir/${marc_type}/zebraexport/authority/exported_records") {
-        my $zebra_auth_cfg = 'zebra-authorities-dom.cfg';
-        system("zebraidx -c $datadir/etc/koha/zebradb/$zebra_auth_cfg  -v none,fatal -g iso2709 -d authorities init");
-        system("zebraidx -c $datadir/etc/koha/zebradb/$zebra_auth_cfg  -v none,fatal -g iso2709 -d authorities update $sourcedir/${marc_type}/zebraexport/authority");
-        system("zebraidx -c $datadir/etc/koha/zebradb/$zebra_auth_cfg  -v none,fatal -g iso2709 -d authorities commit");
-    }
-
-    $child = fork();
-    if ($child == 0) {
-        exec("zebrasrv -f $datadir/etc/koha-conf.xml -v none,request -l $datadir/zebra.log");
-        exit;
-    }
-
-    sleep(1);
-}
-
-sub cleanup {
-    if ($child) {
-        kill 9, $child;
-
-        # Clean up the Zebra files since the child process was just shot
-        rmtree $datadir;
-    }
-}
-
 # Fall back to make sure that the Zebra process
 # and files get cleaned up
-END {
-    cleanup();
-}
+our @cleanup;
 
 sub matchesExplodedTerms {
     my ($message, $query, @terms) = @_;
@@ -211,7 +165,7 @@ our $bibliomodule = Test::MockModule->new('C4::Biblio');
 
 sub mock_GetMarcSubfieldStructure {
     my $marc_type = shift;
-    if ($marc_type eq 'marc21') {
+    if ($marc_type eq 'MARC21') {
         $bibliomodule->mock('GetMarcSubfieldStructure', sub {
             return {
                     'biblio.biblionumber' => [{ tagfield =>  '999', tagsubfield => 'c' }],
@@ -259,14 +213,12 @@ sub mock_GetMarcSubfieldStructure {
 }
 
 sub run_marc21_search_tests {
-    $datadir = tempdir();
-    system(dirname(__FILE__) . "/zebra_config.pl $datadir marc21");
 
-    Koha::Caches->get_instance('config')->flush_all;
+    $marcflavour = 'MARC21';
+    my $mock_zebra = t::lib::Mocks::Zebra->new({marcflavour => $marcflavour});
+    push @cleanup, $mock_zebra;
 
-    mock_GetMarcSubfieldStructure('marc21');
-    my $context = C4::Context->new("$datadir/etc/koha-conf.xml");
-    $context->set_context();
+    mock_GetMarcSubfieldStructure($marcflavour);
 
     use_ok('C4::Search', qw( getIndexes FindDuplicate SimpleSearch getRecords buildQuery searchResults ));
 
@@ -275,7 +227,6 @@ sub run_marc21_search_tests {
     $QueryAutoTruncate = 0;
     $QueryWeightFields = 0;
     $QueryFuzzy = 0;
-    $marcflavour = 'MARC21';
 
     my $indexes = C4::Search::getIndexes();
     is(scalar(grep(/^ti$/, @$indexes)), 1, "Title index supported");
@@ -310,7 +261,23 @@ sub run_marc21_search_tests {
         'VM' => { 'imageurl' => 'bridge/dvd.png', 'summary' => '', 'itemtype' => 'VM', 'description' => 'Visual Materials' },
     );
 
-    index_sample_records_and_launch_zebra($datadir, 'marc21');
+    my $sourcedir = dirname(__FILE__) . "/data";
+    $mock_zebra->load_records(
+        sprintf( "%s/%s/zebraexport/biblio", $sourcedir, lc($marcflavour) ),
+        'iso2709', 'biblios', 1 );
+    $mock_zebra->load_records(
+        sprintf(
+            "%s/%s/zebraexport/large_biblio",
+            $sourcedir, lc($marcflavour)
+        ),
+        'marcxml', 'biblios', 0
+    );
+    $mock_zebra->load_records(
+        sprintf( "%s/%s/zebraexport/authority", $sourcedir, lc($marcflavour) ),
+        'iso2709', 'authorities', 1
+    );
+
+    $mock_zebra->launch_zebra;
 
     my ($biblionumber, $title);
     my $record = MARC::Record->new;
@@ -830,18 +797,16 @@ ok(MARC::Record::new_from_xml($results_hashref->{biblioserver}->{RECORDS}->[0],'
     is_deeply( $facets_info, $expected_facets_info_marc21,
         "_get_facets_info returns the correct data");
 
-    cleanup();
+    $mock_zebra->cleanup;
 }
 
 sub run_unimarc_search_tests {
-    $datadir = tempdir();
-    system(dirname(__FILE__) . "/zebra_config.pl $datadir unimarc");
 
-    Koha::Caches->get_instance('config')->flush_all;
+    $marcflavour = 'UNIMARC';
+    my $mock_zebra = t::lib::Mocks::Zebra->new({marcflavour => $marcflavour});
+    push @cleanup, $mock_zebra;
 
-    mock_GetMarcSubfieldStructure('unimarc');
-    my $context = C4::Context->new("$datadir/etc/koha-conf.xml");
-    $context->set_context();
+    mock_GetMarcSubfieldStructure($marcflavour);
 
     use_ok('C4::Search', qw( getIndexes FindDuplicate SimpleSearch getRecords buildQuery searchResults ));
 
@@ -850,9 +815,23 @@ sub run_unimarc_search_tests {
     $QueryAutoTruncate = 0;
     $QueryWeightFields = 0;
     $QueryFuzzy = 0;
-    $marcflavour = 'UNIMARC';
 
-    index_sample_records_and_launch_zebra($datadir, 'unimarc');
+    my $sourcedir = dirname(__FILE__) . "/data";
+    $mock_zebra->load_records(
+        sprintf( "%s/%s/zebraexport/biblio", $sourcedir, lc($marcflavour) ),
+        'iso2709', 'biblios', 1 );
+    $mock_zebra->load_records(
+        sprintf(
+            "%s/%s/zebraexport/large_biblio",
+            $sourcedir, lc($marcflavour)
+        ),
+        'marcxml', 'biblios', 0
+    );
+    $mock_zebra->load_records(
+        sprintf( "%s/%s/zebraexport/authority", $sourcedir, lc($marcflavour) ),
+        'iso2709', 'authorities', 1
+    );
+    $mock_zebra->launch_zebra;
 
     my ( $error, $marcresults, $total_hits ) = SimpleSearch("ti=Järnvägarnas efterfrågan och den svenska industrin", 0, 10);
     is($total_hits, 1, 'UNIMARC title search');
@@ -916,7 +895,7 @@ sub run_unimarc_search_tests {
     is_deeply( $facets_info, $expected_facets_info_unimarc,
         "_get_facets_info returns the correct data");
 
-    cleanup();
+    $mock_zebra->cleanup;
 }
 
 subtest 'MARC21 + DOM' => sub {
@@ -933,8 +912,8 @@ subtest 'UNIMARC + DOM' => sub {
 subtest 'FindDuplicate' => sub {
     plan tests => 6;
     Koha::Caches->get_instance('config')->flush_all;
-    t::lib::Mocks::mock_preference('marcflavour', 'marc21' );
-    mock_GetMarcSubfieldStructure('marc21');
+    t::lib::Mocks::mock_preference('marcflavour', 'MARC21' );
+    mock_GetMarcSubfieldStructure('MARC21');
     my $z_searcher = Test::MockModule->new('C4::Search');
     $z_searcher->mock('SimpleSearch', sub {
         warn shift @_;
@@ -980,6 +959,8 @@ subtest 'FindDuplicate' => sub {
 Koha::Caches->get_instance('config')->flush_all;
 
 END {
+
+    $_->cleanup for @cleanup;
     my $dbh = C4::Context->dbh;
     # Restore visibility of subfields in OPAC
     $dbh->do(q{
diff --git a/t/db_dependent/selenium/remove_from_cart.t b/t/db_dependent/selenium/remove_from_cart.t
index 02ce186b399..1cefe3178f2 100755
--- a/t/db_dependent/selenium/remove_from_cart.t
+++ b/t/db_dependent/selenium/remove_from_cart.t
@@ -44,11 +44,8 @@ C4::Context->set_preference('SearchEngine', 'Zebra');
 
 my $mock_zebra = t::lib::Mocks::Zebra->new(
     {
-        koha_conf => $ENV{KOHA_CONF},
-        user      => $ENV{KOHA_USER},
-        password  => $ENV{KOHA_PASS},
-        intranet  => $ENV{KOHA_INTRANET_URL},
-        opac      => $ENV{KOHA_OPAC_URL},
+        koha_conf   => $ENV{KOHA_CONF},
+        marcflavour => $marcflavour,
     }
 );
 
diff --git a/t/db_dependent/www/search_utf8.t b/t/db_dependent/www/search_utf8.t
index 4bbfbec8885..70d4e1464c5 100755
--- a/t/db_dependent/www/search_utf8.t
+++ b/t/db_dependent/www/search_utf8.t
@@ -34,9 +34,6 @@ use t::lib::Mocks::Zebra;
 my $testdir = File::Spec->rel2abs( dirname(__FILE__) );
 # global variables that will be used when forking
 
-my $koha_conf = $ENV{KOHA_CONF};
-my $xml       = XMLin($koha_conf);
-
 my $marcflavour = C4::Context->preference('marcflavour') || 'MARC21';
 
 my $file1 =
@@ -54,8 +51,6 @@ my $file3 =
   ? "$testdir/data/unimarcutf8supprec.mrc"
   : "$testdir/data/marc21utf8supprec.mrc";
 
-my $user     = $ENV{KOHA_USER} || $xml->{config}->{user};
-my $password = $ENV{KOHA_PASS} || $xml->{config}->{pass};
 our $intranet = $ENV{KOHA_INTRANET_URL};
 our $opac     = $ENV{KOHA_OPAC_URL};
 
@@ -76,11 +71,9 @@ $opac     =~ s#/$##;
 
 my $mock_zebra = t::lib::Mocks::Zebra->new(
     {
-        koha_conf => $koha_conf,
-        user      => $user,
-        password  => $password,
         intranet  => $intranet,
-        opac      => $opac
+        opac      => $opac,
+        koha_conf => $ENV{KOHA_CONF},
     }
 );
 
@@ -99,12 +92,12 @@ if ( not defined $mock_zebra->{indexer_pid} ) {
 our $agent = Test::WWW::Mechanize->new( autocheck => 1 );
 $agent->get_ok( "$intranet/cgi-bin/koha/mainpage.pl", 'connect to intranet' );
 $agent->form_name('loginform');
-$agent->field( 'password', $password );
-$agent->field( 'userid',   $user );
+$agent->field( 'userid', $ENV{KOHA_PASS} );
+$agent->field( 'password', $ENV{KOHA_USER} );
 $agent->field( 'branch',   '' );
 $agent->click_ok( '', 'login to staff interface' );
 
-my $batch_id = $mock_zebra->load_records($file1);
+my $batch_id = $mock_zebra->load_records_ui($file1);
 my $utf8_reg1 = qr/学協会. μμ/;
 test_search('Αθήνα', 'deuteros', $utf8_reg1);
 $mock_zebra->clean_records($batch_id);
@@ -119,7 +112,7 @@ $mock_zebra->launch_indexer;
 if ( not defined $mock_zebra->{indexer_pid} ) {
     plan skip_all => "Tests skip. Error starting the indexer daemon to do those tests\n";
 }
-$batch_id = $mock_zebra->load_records($file2);
+$batch_id = $mock_zebra->load_records_ui($file2);
 my $utf8_reg2 = qr/Tòmas/;
 test_search('Ramòn', 'Tòmas',$utf8_reg2);
 $mock_zebra->clean_records($batch_id);
@@ -134,7 +127,7 @@ $mock_zebra->launch_indexer;
 if ( not defined $mock_zebra->{indexer_pid} ) {
     plan skip_all => "Tests skip. Error starting the indexer daemon to do those tests\n";
 }
-$batch_id = $mock_zebra->load_records($file3);
+$batch_id = $mock_zebra->load_records_ui($file3);
 my $utf8_reg3 = qr/😀/;
 test_search("𠻺tomasito𠻺", 'A tiny record', $utf8_reg3);
 $mock_zebra->clean_records($batch_id);
diff --git a/t/lib/Mocks/Zebra.pm b/t/lib/Mocks/Zebra.pm
index a20cd8dd9d2..62e8b9480b2 100644
--- a/t/lib/Mocks/Zebra.pm
+++ b/t/lib/Mocks/Zebra.pm
@@ -1,5 +1,20 @@
 package t::lib::Mocks::Zebra;
 
+# 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 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 Test::More;
 use File::Basename qw(dirname );
@@ -8,18 +23,50 @@ use File::Path qw( rmtree );
 use JSON qw( decode_json );
 use C4::ImportBatch;
 
+=head1 NAME
+
+t::lib::Mocks::Zebra - Trying to mock zebra index
+
+IMPORTANT NOTE: This module is not working as you may think it could work.
+
+It will effectively create a new koha-conf.xml file in a temporary directory with zebra config files correctly.
+So it will not affect the koha-conf used by plack (and so the UI).
+
+If you pass koha_conf to the constructor the usual zebra db will be used, otherwise a new koha-conf.xml file will be generated
+and the usual zebra db will not be affected. However you must pass $ENV{KOHA_CONF} if you want to test the UI.
+
+=cut
+
+
 sub new {
     my ( $class, $params ) = @_;
 
-    my $datadir = tempdir();;
+    my $marcflavour = $params->{marcflavour} ? lc($params->{marcflavour}) : 'marc21';
+    my $koha_conf = $params->{koha_conf};
+
+    my $datadir = tempdir();
+    my $zebra_db_dir;
+    unless ( $koha_conf ) {
+        system(dirname(__FILE__) . "/../../db_dependent/zebra_config.pl $datadir $marcflavour");
+
+        Koha::Caches->get_instance('config')->flush_all;
+        $koha_conf = "$datadir/etc/koha-conf.xml";
+        my $context = C4::Context->new($koha_conf);
+        $context->set_context();
+        $zebra_db_dir = "$datadir/etc/koha/zebradb/";
+    } else {
+        $koha_conf = $ENV{KOHA_CONF};
+        $zebra_db_dir = dirname($koha_conf);
+    }
+
     my $self = {
         datadir   => $datadir,
-        koha_conf => $params->{koha_conf},
-        user      => $params->{user},
-        password  => $params->{password},
+        koha_conf => $koha_conf,
+        zebra_db_dir => $zebra_db_dir,
         intranet  => $params->{intranet},
         opac      => $params->{opac}
     };
+
     return bless $self, $class;
 }
 
@@ -30,6 +77,7 @@ sub launch_zebra {
     my $datadir = $self->{datadir};
     my $koha_conf = $self->{koha_conf};
 
+    unlink("$datadir/zebra.log");
     my $zebra_pid = fork();
     if ( $zebra_pid == 0 ) {
         exec("zebrasrv -f $koha_conf -v none,request -l $datadir/zebra.log");
@@ -55,6 +103,25 @@ sub launch_indexer {
 }
 
 sub load_records {
+    my ( $self, $marc_dir, $marc_format, $record_type, $init ) = @_;
+
+    my $datadir = $self->{datadir};
+    my $zebra_cfg = $self->{zebra_db_dir}
+      . ( $record_type eq 'biblios'
+        ? '/zebra-biblios-dom.cfg'
+        : '/zebra-authorities-dom.cfg' );
+
+    my @cmds;
+    push @cmds, "zebraidx -c $zebra_cfg  -v none,fatal -g $marc_format -d $record_type init" if $init;
+    push @cmds, "zebraidx -c $zebra_cfg  -v none,fatal -g $marc_format -d $record_type update $marc_dir";
+    push @cmds, "zebraidx -c $zebra_cfg  -v none,fatal -g $marc_format -d $record_type commit";
+
+    for my $cmd ( @cmds ) {
+        system($cmd);
+    }
+}
+
+sub load_records_ui {
     my ( $self, $file ) = @_;
     my $jsonresponse;
     my $cgi_root = $self->{intranet} . '/cgi-bin/koha';
@@ -62,8 +129,8 @@ sub load_records {
     our $agent = Test::WWW::Mechanize->new( autocheck => 1 );
     $agent->get_ok( "$cgi_root/mainpage.pl", 'connect to intranet' );
     $agent->form_name('loginform');
-    $agent->field( 'password', $self->{password} );
-    $agent->field( 'userid',   $self->{user} );
+    $agent->field( 'userid', $ENV{KOHA_PASS} );
+    $agent->field( 'password', $ENV{KOHA_USER} );
     $agent->field( 'branch',   '' );
     $agent->click_ok( '', 'login to staff interface' );
 
-- 
2.25.1