diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/background_jobs/file_transport_test.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/background_jobs/file_transport_test.inc index 4ed7f7beaa..5ca42c1c87 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/background_jobs/file_transport_test.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/background_jobs/file_transport_test.inc @@ -1,21 +1,22 @@ [% USE Koha %] [%- BLOCK operation_description -%] + [%# Content between SWITCH and its first CASE never executes in Template Toolkit, so "status" must be computed here, before the SWITCH - and against operation.status (the field that actually holds 'error'/'success'), not the nonexistent operation.error. #%] + [%- SET status = operation.status == 'error' ? "failed." : "passed." -%] [%- SWITCH operation.code -%] - [%- IF operation.error %][% SET status = " failed. " %][% ELSE %][% SET status = " passed. " %][% END -%] [%- CASE 'connection' -%] - Connection[% status | html %] + Connection [% status | html %] [%- CASE 'upload' -%] - Upload[% status | html %] + Upload [% status | html %] [%- CASE 'download' -%] - Download[% status | html %] + Download [% status | html %] [%- CASE 'list' -%] - List files[% status | html %] + List files [% status | html %] [%- CASE 'change_directory' -%] - Change directory ([% operation.detail.directory | html %][% operation.detail.operation_params | html %])[% status | html %] + Change directory ([% operation.detail.directory | html %][% operation.detail.operation_params | html %]) [% status | html %] [%- CASE -%] - [% operation.code | html %][% status | html %] + [% operation.code | html %] [% status | html %] [%- END -%] [%- END -%] diff --git a/t/db_dependent/Koha/BackgroundJob/TestTransport.t b/t/db_dependent/Koha/BackgroundJob/TestTransport.t new file mode 100755 index 0000000000..b440ffbc50 --- /dev/null +++ b/t/db_dependent/Koha/BackgroundJob/TestTransport.t @@ -0,0 +1,126 @@ +#!/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::More tests => 2; +use Test::NoWarnings; +use Test::MockModule; +use JSON qw( decode_json ); +use File::Temp qw( tempdir ); +use File::Spec; + +use Koha::Database; +use Koha::BackgroundJobs; +use Koha::BackgroundJob::TestTransport; +use Koha::File::Transports; + +use t::lib::TestBuilder; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; + +subtest 'process() records the full trace (successes and the failure), not only the last error' => sub { + plan tests => 8; + + $schema->storage->txn_begin; + + my $tempdir = tempdir( CLEANUP => 1 ); + my $download_dir = File::Spec->catdir( $tempdir, 'download' ); + my $upload_dir = File::Spec->catdir( $tempdir, 'upload' ); + mkdir $download_dir or die "Cannot create download_dir: $!"; + mkdir $upload_dir or die "Cannot create upload_dir: $!"; + + my $transport = $builder->build_object( + { + class => 'Koha::File::Transports', + value => { + transport => 'local', + download_directory => $download_dir, + upload_directory => $upload_dir, + } + } + ); + + # test_connection() calls list_files() once per configured direction + # (download, then upload). Simulate a real "some steps pass, one fails" + # run: the first call (download) succeeds, the second (upload) fails. + my $call_count = 0; + my $mock_local = Test::MockModule->new('Koha::File::Transport::Local'); + $mock_local->mock( + '_list_files', + sub { + my ($self) = @_; + $call_count++; + if ( $call_count == 1 ) { + $self->add_message( + { message => 'list', type => 'success', payload => { path => $download_dir, count => 0 } } ); + return []; + } else { + $self->add_message( + { + message => 'list', type => 'error', + payload => { error => 'Simulated failure', path => $upload_dir } + } + ); + return; + } + } + ); + + my $job_id = Koha::BackgroundJob::TestTransport->new->enqueue( { transport_id => $transport->id } ); + my $job = Koha::BackgroundJobs->find($job_id)->_derived_class; + + $job->process( { transport_id => $transport->id } ); + + is( $job->status, 'finished', 'job finished' ); + + my $data = $job->decoded_data; + is( $data->{status}, 'errors', 'overall job status is "errors" because one operation failed' ); + + my @codes = map { $_->{code} } @{ $data->{operations} }; + ok( + scalar(@codes) > 1, + 'more than one operation was recorded - the trace is not collapsed to just the final error' + ); + + my @statuses = map { $_->{status} } @{ $data->{operations} }; + ok( ( grep { $_ eq 'success' } @statuses ), 'at least one recorded operation is a success' ); + ok( ( grep { $_ eq 'error' } @statuses ), 'at least one recorded operation is an error' ); + + # Order matters for display: successes should appear before the failure + # they preceded, not just the failure on its own. + my ($first_error_index) = grep { $statuses[$_] eq 'error' } 0 .. $#statuses; + ok( + ( grep { $_ eq 'success' } @statuses[ 0 .. $first_error_index - 1 ] ), + 'a success is recorded before the failing operation, preserving the full sequence' + ); + + # The transport's own status column (read by the admin UI) should match + # what was persisted by TestTransport::process(), not something narrower. + my $reloaded = Koha::File::Transports->find( $transport->id ); + my $persisted_status = decode_json( $reloaded->status ); + is( $persisted_status->{status}, 'errors', q{the transport's own status column matches the job's} ); + is( + scalar @{ $persisted_status->{operations} }, scalar @codes, + q{the transport's own status column carries the same full trace, not a single collapsed entry} + ); + + $schema->storage->txn_rollback; +}; + +1;