Bug 41918: (QA follow-up) Add unit tests for Koha::Reports->running
Adds a 'running' subtest covering the new method: - Returns a Koha::Reports resultset (object identity, not opaque ids). - Returns an empty resultset when nothing is in flight, and when the user_id / report_id filter does not match any process. - Parses saved_sql.id markers out of synthetic processlist rows and resolves them to real Koha::Report objects, ignoring rows without the marker. - Sends parameterised LIKE binds for user_id (proves the WHERE clause is built without string interpolation). - Falls back to an empty resultset and does not propagate the exception when the underlying selectall_arrayref call dies, eg. when the database user lacks PROCESS privilege. To make the failure path mockable without trying to mock DBI::db (which is not loadable as a separate file), the dbh selectall is extracted into a tiny Koha::Reports::_processlist_rows helper so Test::MockModule can replace it cleanly. The helper is otherwise behaviour-preserving. Test plan: 1) prove t/db_dependent/Koha/Reports.t -> 11 tests, all pass. 2) Existing prep_report subtest still passes. Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
parent
081e895ccb
commit
c8f0f064d6
|
|
@ -79,9 +79,8 @@ sub running {
|
|||
|
||||
my $sql = 'SELECT info FROM information_schema.processlist WHERE ' . join( ' AND ', @where );
|
||||
|
||||
my $schema = Koha::Database->new->schema;
|
||||
my $rows;
|
||||
eval { $rows = $schema->storage->dbh->selectall_arrayref( $sql, { Slice => {} }, @binds ); };
|
||||
eval { $rows = $class->_processlist_rows( $sql, @binds ); };
|
||||
if ($@) {
|
||||
Koha::Logger->get->warn("Koha::Reports->running: unable to query information_schema.processlist: $@");
|
||||
$rows = [];
|
||||
|
|
@ -95,6 +94,11 @@ sub running {
|
|||
return $class->search( { id => { -in => [ keys %report_ids ] } } );
|
||||
}
|
||||
|
||||
sub _processlist_rows {
|
||||
my ( $class, $sql, @binds ) = @_;
|
||||
return Koha::Database->new->schema->storage->dbh->selectall_arrayref( $sql, { Slice => {} }, @binds );
|
||||
}
|
||||
|
||||
=head3 _type
|
||||
|
||||
Returns name of corresponding DBIC resultset
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@
|
|||
|
||||
use Modern::Perl;
|
||||
|
||||
use Test::MockModule;
|
||||
use Test::NoWarnings;
|
||||
use Test::More tests => 10;
|
||||
use Test::More tests => 11;
|
||||
|
||||
use Koha::Report;
|
||||
use Koha::Reports;
|
||||
|
|
@ -213,4 +214,66 @@ subtest 'apply_execution_time_limit' => sub {
|
|||
);
|
||||
};
|
||||
|
||||
subtest 'running' => sub {
|
||||
plan tests => 7;
|
||||
|
||||
my $running = Koha::Reports->running;
|
||||
isa_ok( $running, 'Koha::Reports', 'running() returns a Koha::Reports resultset' );
|
||||
|
||||
# No saved-report SQL is in flight in the test process; processlist may show
|
||||
# this very test connection but its current statement carries no saved_sql.id
|
||||
# marker, so the result must be empty.
|
||||
is( Koha::Reports->running->count, 0, 'no running reports => empty resultset' );
|
||||
|
||||
is(
|
||||
Koha::Reports->running( { user_id => 999_999_999 } )->count, 0,
|
||||
'unknown user_id => empty resultset'
|
||||
);
|
||||
is(
|
||||
Koha::Reports->running( { report_id => 999_999_999 } )->count, 0,
|
||||
'unknown report_id => empty resultset'
|
||||
);
|
||||
|
||||
# Capture the SQL bindings and feed synthetic rows back; this exercises the
|
||||
# WHERE-clause assembly and the saved_sql.id parser without relying on a
|
||||
# real long-running query in the database.
|
||||
my $reports_mock = Test::MockModule->new('Koha::Reports');
|
||||
my @captured_binds;
|
||||
my $synthetic_rows = [];
|
||||
$reports_mock->mock(
|
||||
'_processlist_rows',
|
||||
sub {
|
||||
my ( $class, $sql, @binds ) = @_;
|
||||
push @captured_binds, [@binds];
|
||||
return $synthetic_rows;
|
||||
}
|
||||
);
|
||||
|
||||
my $report_a = $builder->build_object( { class => 'Koha::Reports' } );
|
||||
my $report_b = $builder->build_object( { class => 'Koha::Reports' } );
|
||||
my ( $a_id, $b_id ) = ( $report_a->id, $report_b->id );
|
||||
|
||||
$synthetic_rows = [
|
||||
{ info => "SELECT 1 /* { saved_sql.id: $a_id } { user_id: 17 } */" },
|
||||
{ info => "SELECT 1 /* { saved_sql.id: $b_id } { user_id: 18 } */" },
|
||||
{ info => "SELECT 1 /* no marker, should be ignored */" },
|
||||
];
|
||||
is( Koha::Reports->running->count, 2, 'parses saved_sql.id markers and returns matching reports' );
|
||||
|
||||
@captured_binds = ();
|
||||
Koha::Reports->running( { user_id => 17 } );
|
||||
is_deeply(
|
||||
$captured_binds[0],
|
||||
[ 'Sleep', '%saved_sql.id:%', '%{ user_id: 17 }%' ],
|
||||
'user_id contributes a parameterised LIKE bind'
|
||||
);
|
||||
|
||||
# Graceful degradation when the underlying DB call dies (eg. PROCESS denied).
|
||||
$reports_mock->mock( '_processlist_rows', sub { die "Access denied for user\n"; } );
|
||||
is(
|
||||
Koha::Reports->running->count, 0,
|
||||
'DB failure => empty resultset (caller is not aborted)'
|
||||
);
|
||||
};
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
|
|
|
|||
Loading…
Reference in New Issue