3 # This file is part of Koha
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
22 use Test::More tests => 5;
27 use Koha::BackgroundJobs;
28 use Koha::BackgroundJob::BatchUpdateItem;
31 use t::lib::Mocks::Logger;
32 use t::lib::TestBuilder;
33 use t::lib::Koha::BackgroundJob::BatchTest;
35 my $logger = t::lib::Mocks::Logger->new;
36 my $schema = Koha::Database->new->schema;
37 my $builder = t::lib::TestBuilder->new;
39 subtest '_derived_class() tests' => sub {
43 $schema->storage->txn_begin;
45 my $job_object = Koha::BackgroundJob->new();
46 my $mapping = $job_object->type_to_class_mapping;
49 my $type = ( keys %{$mapping} )[0];
51 my $job = $builder->build_object(
52 { class => 'Koha::BackgroundJobs',
53 value => { type => $type, data => 'Foo' }
57 my $derived = $job->_derived_class;
59 is( ref($derived), $mapping->{$type}, 'Job object class is correct' );
60 ok( $derived->in_storage, 'The object is correctly marked as in storage' );
62 $derived->data('Bar')->store->discard_changes;
63 $job->discard_changes;
65 is_deeply( $job->unblessed, $derived->unblessed, '_derived_class object refers to the same DB object and can be manipulated as expected' );
67 $schema->storage->txn_rollback;
70 subtest 'enqueue() tests' => sub {
74 $schema->storage->txn_begin;
76 # FIXME: This all feels we need to do it better...
77 my $job_id = Koha::BackgroundJob::BatchUpdateItem->new->enqueue( { record_ids => [ 1, 2 ] } );
78 my $job = Koha::BackgroundJobs->find($job_id)->_derived_class;
80 is( $job->size, 2, 'Two steps' );
81 is( $job->status, 'new', 'Initial status set correctly' );
82 is( $job->borrowernumber, undef, 'No userenv, borrowernumber undef' );
84 my $interface = C4::Context->interface;
85 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
86 t::lib::Mocks::mock_userenv( { patron => $patron } );
88 number => $patron->borrowernumber,
89 id => $patron->userid,
90 cardnumber => $patron->cardnumber,
91 firstname => $patron->firstname,
92 surname => $patron->surname,
93 branch => $patron->library->branchcode,
94 branchname => $patron->library->branchname,
95 flags => $patron->flags,
96 emailaddress => $patron->email,
98 register_name => undef,
102 interface => $interface
105 $job_id = Koha::BackgroundJob::BatchUpdateItem->new->enqueue( { record_ids => [ 1, 2, 3 ] } );
106 $job = Koha::BackgroundJobs->find($job_id)->_derived_class;
108 is( $job->size, 3, 'Three steps' );
109 is( $job->status, 'new', 'Initial status set correctly' );
110 is( $job->borrowernumber, $patron->id, 'Borrowernumber set from userenv' );
111 is_deeply( $job->json->decode( $job->context ), $job_context, 'Context set from userenv + interface' );
113 $schema->storage->txn_rollback;
116 subtest 'start(), step() and finish() tests' => sub {
120 $schema->storage->txn_begin;
122 # FIXME: This all feels we need to do it better...
123 my $job_id = Koha::BackgroundJob::BatchUpdateItem->new->enqueue( { record_ids => [ 1, 2 ] } );
124 my $job = Koha::BackgroundJobs->find($job_id)->_derived_class;
126 is( $job->started_on, undef, 'started_on not set yet' );
127 is( $job->size, 2, 'Two steps' );
131 isnt( $job->started_on, undef, 'started_on set' );
132 is( $job->status, 'started' );
133 is( $job->progress, 0, 'No progress yet' );
136 is( $job->progress, 1, 'First step' );
138 is( $job->progress, 2, 'Second step' );
141 'Koha::Exceptions::BackgroundJob::StepOutOfBounds',
142 'Tried to make a forbidden extra step';
144 is( $job->progress, 2, 'progress remains unchanged' );
146 my $data = { some => 'data' };
148 $job->status('cancelled')->store;
149 $job->finish( $data );
151 is( $job->status, 'cancelled', "'finish' leaves 'cancelled' untouched" );
152 isnt( $job->ended_on, undef, 'ended_on set' );
153 is_deeply( $job->json->decode( $job->data ), $data );
155 $job->status('started')->store;
156 $job->finish( $data );
158 is( $job->status, 'finished' );
159 isnt( $job->ended_on, undef, 'ended_on set' );
160 is_deeply( $job->json->decode( $job->data ), $data );
164 'Koha::Exceptions::BackgroundJob::InconsistentStatus',
165 'Exception thrown trying to start a finished job';
167 is( $@->expected_status, 'new' );
171 'Koha::Exceptions::BackgroundJob::InconsistentStatus',
172 'Exception thrown trying to start a finished job';
174 is( $@->expected_status, 'started' );
176 $schema->storage->txn_rollback;
179 subtest 'process tests' => sub {
183 $schema->storage->txn_begin;
185 C4::Context->interface('intranet');
186 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
187 t::lib::Mocks::mock_userenv( { patron => $patron } );
189 number => $patron->borrowernumber,
190 id => $patron->userid,
191 cardnumber => $patron->cardnumber,
192 firstname => $patron->firstname,
193 surname => $patron->surname,
194 branch => $patron->library->branchcode,
195 branchname => $patron->library->branchname,
196 flags => $patron->flags,
197 emailaddress => $patron->email,
198 register_id => undef,
199 register_name => undef,
205 my $background_job_module = Test::MockModule->new('Koha::BackgroundJob');
206 $background_job_module->mock(
207 'type_to_class_mapping',
209 return { batch_test => 't::lib::Koha::BackgroundJob::BatchTest' };
213 my $job_id = t::lib::Koha::BackgroundJob::BatchTest->new->enqueue(
214 { size => 10, a => 'aaa', b => 'bbb' } );
215 my $job = Koha::BackgroundJobs->find($job_id);
217 C4::Context->_new_userenv(-1);
218 C4::Context->interface('opac');
219 is( C4::Context->userenv, undef, "Userenv unset prior to calling process");
220 is( C4::Context->interface, 'opac', "Interface set to opac prior to calling process");
223 is_deeply( C4::Context->userenv, $job_context, "Userenv set from job context on process" );
224 is_deeply( C4::Context->interface, 'intranet', "Interface set from job context on process" );
226 # Manually add a job (->new->store) without context
227 my $json = $job->json; # sorry, quickly borrowing your json object
228 my $data = $json->encode({ a => 'a', b => 'b' });
229 my $incomplete_job = t::lib::Koha::BackgroundJob::BatchTest->new(
232 borrowernumber => $patron->borrowernumber,
233 type => 'batch_test',
238 $incomplete_job = Koha::BackgroundJobs->find( $incomplete_job->id );
239 $incomplete_job->process();
240 $logger->warn_is( "A background job didn't have context defined (" . $incomplete_job->id . ")" );
242 $schema->storage->txn_rollback;
245 subtest 'decoded_data() and set_encoded_data() tests' => sub {
248 $schema->storage->txn_begin;
250 my $job = Koha::BackgroundJob::BatchUpdateItem->new->set_encoded_data( undef );
251 is( $job->decoded_data, undef, 'undef is undef' );
253 my $data = { some => 'data' };
255 $job->set_encoded_data( $data );
257 is_deeply( $job->json->decode($job->data), $data, 'decode what we sent' );
258 is_deeply( $job->decoded_data, $data, 'check with decoded_data' );
260 # Let's get some Unicode stuff into the game
261 $data = { favorite_Chinese => [ '葑', '癱' ], latin_dancing => [ '¢', '¥', 'á', 'û' ] };
262 $job->set_encoded_data( $data )->store;
264 $job->discard_changes; # refresh
265 is_deeply( $job->decoded_data, $data, 'Deep compare with Unicode data' );
266 # To convince you even more
267 is( ord( $job->decoded_data->{favorite_Chinese}->[0] ), 33873, 'We still found Unicode \x8451' );
268 is( ord( $job->decoded_data->{latin_dancing}->[0] ), 162, 'We still found the equivalent of Unicode \x00A2' );
270 # Testing with sending encoded data (which we normally shouldn't do)
272 foreach my $k ( 'favorite_Chinese', 'latin_dancing' ) {
273 foreach my $c ( @{$data->{$k}} ) {
274 push @{$utf8_data->{$k}}, Encode::encode('UTF-8', $c);
277 $job->set_encoded_data( $utf8_data )->store;
278 $job->discard_changes; # refresh
279 is_deeply( $job->decoded_data, $utf8_data, 'Deep compare with utf8_data' );
280 # Need more evidence?
281 is( ord( $job->decoded_data->{favorite_Chinese}->[0] ), 232, 'We still found a UTF8 encoded byte' ); # ord does not need substr here
283 $schema->storage->txn_rollback;