From d341e3b54c518f6d05020d41e0cc7cd4ac36120e Mon Sep 17 00:00:00 2001 From: Arthur Suzuki Date: Mon, 17 Nov 2025 15:11:35 +0000 Subject: [PATCH] Bug 20125: (QA follow-up) Add script testing --- t/db_dependent/cronjobs/orders_claim.t | 356 +++++++++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100755 t/db_dependent/cronjobs/orders_claim.t diff --git a/t/db_dependent/cronjobs/orders_claim.t b/t/db_dependent/cronjobs/orders_claim.t new file mode 100755 index 0000000000..3c276a87cb --- /dev/null +++ b/t/db_dependent/cronjobs/orders_claim.t @@ -0,0 +1,356 @@ +#!/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 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 . + +use Modern::Perl; + +use Test::NoWarnings; +use Test::More tests => 4; +use t::lib::TestBuilder; +use t::lib::Mocks; +use File::Spec; +use File::Basename; + +use Koha::DateUtils qw( dt_from_string ); + +my $scriptDir = dirname( File::Spec->rel2abs(__FILE__) ); + +my $schema = Koha::Database->new->schema; +my $dbh = C4::Context->dbh; + +my $library1; +my $library2; +my $basket1; +my $basket2; +my $bookseller1; +my $bookseller2; +my $contact1; +my $contact2; +my $order1; +my $order2; +my $order3; + +sub build_test_objects { + t::lib::Mocks::mock_preference( 'dateformat', 'metric' ); + + my $builder = t::lib::TestBuilder->new; + + $library1 = $builder->build( + { + source => 'Branch', + } + ); + $library2 = $builder->build( + { + source => 'Branch', + } + ); + + $bookseller1 = $builder->build( + { + source => 'Aqbookseller', + value => { + name => 'Bookseller 1', + deliverytime => 10, + } + } + ); + + $bookseller2 = $builder->build( + { + source => 'Aqbookseller', + value => { + name => 'Bookseller 2', + deliverytime => 15, + } + } + ); + + $contact1 = $builder->build( + { + source => 'Aqcontact', + value => { + booksellerid => $bookseller1->{id}, + claimacquisition => 1, + email => 'contact1@example.com', + } + } + ); + + $contact2 = $builder->build( + { + source => 'Aqcontact', + value => { + booksellerid => $bookseller2->{id}, + claimacquisition => 1, + email => 'contact2@example.com', + } + } + ); + + $basket1 = $builder->build( + { + source => 'Aqbasket', + value => { + booksellerid => $bookseller1->{id}, + branch => $library1->{branchcode}, + basketname => 'Basket 1', + } + } + ); + + $basket2 = $builder->build( + { + source => 'Aqbasket', + value => { + booksellerid => $bookseller2->{id}, + branch => $library2->{branchcode}, + basketname => 'Basket 2', + } + } + ); + + # Create a budget for orders + my $bpid = C4::Budgets::AddBudgetPeriod( + { + budget_period_startdate => '2008-01-01', + budget_period_enddate => '2008-12-31', + budget_period_active => 1, + budget_period_description => "TEST_PERIOD" + } + ); + + my $budgetid = C4::Budgets::AddBudget( + { + budget_code => "TEST_BUDGET", + budget_name => "Test Budget", + budget_period_id => $bpid, + } + ); + + my $budget = C4::Budgets::GetBudget($budgetid); + + # Create test orders using the same style as Acquisition.t + my @order_content = ( + { + str => { + basketno => $basket1->{basketno}, + biblionumber => $builder->build_sample_biblio( { title => 'Test Title 1' } )->biblionumber, + budget_id => $budget->{budget_id}, + orderstatus => 'ordered', + entrydate => dt_from_string->subtract( days => 20 ), + quantity => 2, + listprice => 10.00, + }, + num => { + quantity => 2, + } + }, + { + str => { + basketno => $basket1->{basketno}, + biblionumber => $builder->build_sample_biblio( { title => 'Test Title 2' } )->biblionumber, + budget_id => $budget->{budget_id}, + orderstatus => 'ordered', + entrydate => dt_from_string->subtract( days => 25 ), + quantity => 1, + listprice => 15.00, + }, + num => { + quantity => 1, + } + }, + { + str => { + basketno => $basket2->{basketno}, + biblionumber => $builder->build_sample_biblio( { title => 'Test Title 3' } )->biblionumber, + budget_id => $budget->{budget_id}, + orderstatus => 'ordered', + entrydate => dt_from_string->subtract( days => 30 ), + quantity => 3, + listprice => 20.00, + }, + num => { + quantity => 3, + } + } + ); + + # Create orders in database + my @ordernumbers; + for ( 0 .. 2 ) { + my %ocontent; + @ocontent{ keys %{ $order_content[$_]->{num} } } = values %{ $order_content[$_]->{num} }; + @ocontent{ keys %{ $order_content[$_]->{str} } } = values %{ $order_content[$_]->{str} }; + $ordernumbers[$_] = Koha::Acquisition::Order->new( \%ocontent )->store->ordernumber; + $order_content[$_]->{str}->{ordernumber} = $ordernumbers[$_]; + } + + # Close the baskets to make orders late + my $basket1_obj = Koha::Acquisition::Baskets->find( $basket1->{basketno} ); + my $basket2_obj = Koha::Acquisition::Baskets->find( $basket2->{basketno} ); + + # Set closedate to a date that would make the orders late + my $late_date = dt_from_string->subtract( days => 30 ); + $basket1_obj->closedate($late_date); + $basket1_obj->store; + $basket2_obj->closedate($late_date); + $basket2_obj->store; + + $order1 = Koha::Acquisition::Orders->find( $ordernumbers[0] ); + $order2 = Koha::Acquisition::Orders->find( $ordernumbers[1] ); + $order3 = Koha::Acquisition::Orders->find( $ordernumbers[2] ); +} + +sub run_script { + my $script = shift; + local @ARGV = @_; + + # We simulate script execution by evaluating the script code in the context + # of this unit test. + + eval $script; ## no critic (StringyEval) + + die $@ if $@; +} + +# Load the script content once +my $scriptContent = ''; +my $scriptFile = "$scriptDir/../../../misc/cronjobs/ordersClaim.pl"; +open my $scriptfh, "<", $scriptFile or die "Failed to open $scriptFile: $!"; + +while (<$scriptfh>) { + $scriptContent .= $_; +} +close $scriptfh; + +# Evaluate the script content once to define all subroutines +{ + local @ARGV = (); + eval $scriptContent; ## no critic (StringyEval) + die $@ if $@; +} + +my $sthmq = $dbh->prepare('SELECT * FROM message_queue WHERE to_address = ?'); + +subtest 'Default behaviour tests' => sub { + + plan tests => 2; + + $schema->storage->txn_begin; + + build_test_objects(); + + # Set up arguments for the script + @ARGV = ( 'ordersClaim.pl', '--delay', '15', '--claimed-for', '5', '--max-claims', '2' ); + + # Parse arguments as the script would + my $help; + my $delay = 15; + my $claimed_for = 5; + my $max_claims = 2; + my $letter_code = 'ACQCLAIM'; + + # Process the orders directly using the subroutines + my $late_orders = get_late_orders($delay); + my $baskets_orders = get_basket_orders($late_orders); + + while ( my ( $basketno, $orderids ) = each %$baskets_orders ) { + process_basket( $basketno, $orderids, $max_claims, $claimed_for, $letter_code ); + } + + $sthmq->execute('contact1@example.com'); + + my $messages = $sthmq->fetchall_hashref('message_id'); + + is( scalar( keys %$messages ), 1, 'There is one message in the queue for contact1' ); + + $sthmq->execute('contact2@example.com'); + + $messages = $sthmq->fetchall_hashref('message_id'); + + is( scalar( keys %$messages ), 1, 'There is one message in the queue for contact2' ); + + $schema->storage->txn_rollback; +}; + +subtest 'No orders found tests' => sub { + + plan tests => 1; + + $schema->storage->txn_begin; + + build_test_objects(); + + $dbh->do('DELETE FROM aqorders'); + + # Set up arguments for the script + @ARGV = ( 'ordersClaim.pl', '--delay', '15', '--claimed-for', '5', '--max-claims', '2' ); + + # Parse arguments as the script would + my $help; + my $delay = 15; + my $claimed_for = 5; + my $max_claims = 2; + my $letter_code = 'ACQCLAIM'; + + # Process the orders directly using the subroutines + my $late_orders = get_late_orders($delay); + my $baskets_orders = get_basket_orders($late_orders); + + while ( my ( $basketno, $orderids ) = each %$baskets_orders ) { + process_basket( $basketno, $orderids, $max_claims, $claimed_for, $letter_code ); + } + + $sthmq->execute('contact1@example.com'); + + my $messages = $sthmq->fetchall_hashref('message_id'); + + is( scalar( keys %$messages ), 0, 'There are no messages in the queue for contact1 when no orders exist' ); + + $schema->storage->txn_rollback; +}; + +subtest 'Error handling tests' => sub { + + plan tests => 1; + + $schema->storage->txn_begin; + + build_test_objects(); + + # Set up arguments for the script + @ARGV = ( 'ordersClaim.pl', '--delay', '15', '--claimed-for', '5', '--max-claims', '2' ); + + # Parse arguments as the script would + my $help; + my $delay = 15; + my $claimed_for = 5; + my $max_claims = 2; + my $letter_code = 'ACQCLAIM'; + + # Process the orders directly using the subroutines + my $late_orders = get_late_orders($delay); + my $baskets_orders = get_basket_orders($late_orders); + + while ( my ( $basketno, $orderids ) = each %$baskets_orders ) { + process_basket( $basketno, $orderids, $max_claims, $claimed_for, $letter_code ); + } + + ok( 1, 'Script runs without crashing on missing basket' ); + + $schema->storage->txn_rollback; +}; -- 2.39.5