Bug 16699: Remove requirement from borrowernumberQueryParam
[koha.git] / t / db_dependent / TestBuilder.t
blob3046ad8580c1a7395e16c18e9dce71de5798b4b1
1 #!/usr/bin/perl
3 # This file is part of Koha.
5 # Copyright 2014 - Biblibre SARL
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
20 use Modern::Perl;
22 use Test::More tests => 10;
23 use Test::Warn;
24 use Data::Dumper qw(Dumper);
26 use Koha::Database;
28 BEGIN {
29 use_ok('t::lib::TestBuilder');
32 my $schema = Koha::Database->new->schema;
33 $schema->storage->txn_begin;
34 my $builder;
37 subtest 'Start with some trivial tests' => sub {
38 plan tests => 6;
40 $builder = t::lib::TestBuilder->new;
41 isnt( $builder, undef, 'We got a builder' );
43 is( $builder->build, undef, 'build without arguments returns undef' );
44 is( ref( $builder->schema ), 'Koha::Schema', 'check schema' );
45 is( ref( $builder->can('delete') ), 'CODE', 'found delete method' );
47 # invalid argument
48 warning_like { $builder->build({
49 source => 'Borrower',
50 value => { surname => { invalid_hash => 1 } },
51 }) } qr/^Hash not allowed for surname/,
52 'Build should not accept a hash for this column';
54 # return undef if a record exists
55 my $branchcode = $builder->build({ source => 'Branch' })->{branchcode};
56 my $param = { source => 'Branch', value => { branchcode => $branchcode } };
57 warning_like { $builder->build( $param ) }
58 qr/Violation of unique constraint/,
59 'Catch warn on adding existing record';
63 subtest 'Build all sources' => sub {
64 plan tests => 1;
66 my @sources = $builder->schema->sources;
67 my @source_in_failure;
68 for my $source ( @sources ) {
69 my $res;
70 eval { $res = $builder->build( { source => $source } ); };
71 push @source_in_failure, $source if $@ || !defined( $res );
73 is( @source_in_failure, 0,
74 'TestBuilder should be able to create an object for every source' );
75 if ( @source_in_failure ) {
76 diag( "The following sources have not been generated correctly: " .
77 join ', ', @source_in_failure );
82 subtest 'Test length of some generated fields' => sub {
83 plan tests => 2;
85 # Test the length of a returned character field
86 my $bookseller = $builder->build({ source => 'Aqbookseller' });
87 my $max = $schema->source('Aqbookseller')->column_info('phone')->{size};
88 is( length( $bookseller->{phone} ) > 0, 1,
89 'The length for a generated string (phone) should not be zero' );
90 is( length( $bookseller->{phone} ) <= $max, 1,
91 'Check maximum length for a generated string (phone)' );
95 subtest 'Test FKs in overduerules_transport_type' => sub {
96 plan tests => 5;
98 my $my_overduerules_transport_type = {
99 message_transport_type => {
100 message_transport_type => 'my msg_t_t',
102 overduerules_id => {
103 branchcode => 'codeB',
104 categorycode => 'codeC',
108 my $overduerules_transport_type = $builder->build({
109 source => 'OverduerulesTransportType',
110 value => $my_overduerules_transport_type,
113 $overduerules_transport_type->{message_transport_type},
114 $my_overduerules_transport_type->{message_transport_type}->{message_transport_type},
115 'build stores the message_transport_type correctly'
118 $schema->resultset('Overduerule')->find( $overduerules_transport_type->{overduerules_id} )->branchcode,
119 $my_overduerules_transport_type->{overduerules_id}->{branchcode},
120 'build stores the branchcode correctly'
123 $schema->resultset('Overduerule')->find( $overduerules_transport_type->{overduerules_id} )->categorycode,
124 $my_overduerules_transport_type->{overduerules_id}->{categorycode},
125 'build stores the categorycode correctly'
128 $schema->resultset('MessageTransportType')->find( $overduerules_transport_type->{message_transport_type} )->message_transport_type,
129 $overduerules_transport_type->{message_transport_type},
130 'build stores the foreign key message_transport_type correctly'
132 isnt(
133 $schema->resultset('Overduerule')->find( $my_overduerules_transport_type->{overduerules_id} )->letter2,
134 undef,
135 'build generates values if they are not given'
140 subtest 'Tests with composite FK in userpermission' => sub {
141 plan tests => 9;
143 my $my_user_permission = default_userpermission();
144 my $user_permission = $builder->build({
145 source => 'UserPermission',
146 value => $my_user_permission,
149 # Checks on top level of userpermission
150 isnt(
151 $user_permission->{borrowernumber},
152 undef,
153 'build generates a borrowernumber correctly'
156 $user_permission->{code},
157 $my_user_permission->{code}->{code},
158 'build stores code correctly'
161 # Checks one level deeper userpermission -> borrower
162 my $patron = $schema->resultset('Borrower')->find({ borrowernumber => $user_permission->{borrowernumber} });
164 $patron->surname,
165 $my_user_permission->{borrowernumber}->{surname},
166 'build stores surname correctly'
168 isnt(
169 $patron->cardnumber,
170 undef,
171 'build generated cardnumber'
174 # Checks two levels deeper userpermission -> borrower -> branch
175 my $branch = $schema->resultset('Branch')->find({ branchcode => $patron->branchcode->branchcode });
177 $branch->branchname,
178 $my_user_permission->{borrowernumber}->{branchcode}->{branchname},
179 'build stores branchname correctly'
181 isnt(
182 $branch->branchaddress1,
183 undef,
184 'build generated branch address'
187 # Checks with composite FK: userpermission -> permission
188 my $perm = $schema->resultset('Permission')->find({ module_bit => $user_permission->{module_bit}, code => $my_user_permission->{code}->{code} });
189 isnt( $perm, undef, 'build generated record for composite FK' );
191 $perm->code,
192 $my_user_permission->{code}->{code},
193 'build stored code correctly'
196 $perm->description,
197 $my_user_permission->{code}->{description},
198 'build stored description correctly'
202 sub default_userpermission {
203 return {
204 borrowernumber => {
205 surname => 'my surname',
206 address => 'my adress',
207 city => 'my city',
208 branchcode => {
209 branchname => 'my branchname',
211 categorycode => {
212 hidelostitems => 0,
213 category_type => 'A',
214 default_privacy => 'default',
216 privacy => 1,
218 module_bit => {
219 flag => 'my flag',
221 code => {
222 code => 'my code',
223 description => 'my desc',
229 subtest 'Test build with NULL values' => sub {
230 plan tests => 3;
232 # PK should not be null
233 my $params = { source => 'Branch', value => { branchcode => undef }};
234 warning_like { $builder->build( $params ) }
235 qr/Null value for branchcode/,
236 'Catch warn on adding branch with a null branchcode';
237 # Nullable column
238 my $info = $schema->source( 'Item' )->column_info( 'barcode' );
239 $params = { source => 'Item', value => { barcode => undef }};
240 my $item = $builder->build( $params );
241 is( $info->{is_nullable} && $item && !defined( $item->{barcode} ), 1,
242 'Barcode can be NULL' );
243 # Nullable FK
244 $params = { source => 'Reserve', value => { itemnumber => undef }};
245 my $reserve = $builder->build( $params );
246 $info = $schema->source( 'Reserve' )->column_info( 'itemnumber' );
247 is( $reserve && $info->{is_nullable} && $info->{is_foreign_key} &&
248 !defined( $reserve->{itemnumber} ), 1, 'Nullable FK' );
252 subtest 'Tests for delete method' => sub {
253 plan tests => 12;
255 # Test delete with single and multiple records
256 my $basket1 = $builder->build({ source => 'Aqbasket' });
257 my $basket2 = $builder->build({ source => 'Aqbasket' });
258 my $basket3 = $builder->build({ source => 'Aqbasket' });
259 my ( $id1, $id2 ) = ( $basket1->{basketno}, $basket2->{basketno} );
260 $builder->delete({ source => 'Aqbasket', records => $basket1 });
261 isnt( exists $basket1->{basketno}, 1, 'Delete cleared PK hash value' );
263 is( $builder->schema->resultset('Aqbasket')->search({ basketno => $id1 })->count, 0, 'Basket1 is no longer found' );
264 is( $builder->schema->resultset('Aqbasket')->search({ basketno => $id2 })->count, 1, 'Basket2 is still found' );
265 is( $builder->delete({ source => 'Aqbasket', records => [ $basket2, $basket3 ] }), 2, "Returned two delete attempts" );
266 is( $builder->schema->resultset('Aqbasket')->search({ basketno => $id2 })->count, 0, 'Basket2 is no longer found' );
269 # Test delete in table without primary key (..)
270 is( $schema->source('TmpHoldsqueue')->primary_columns, 0,
271 'Table without primary key detected' );
272 my $bibno = 123; # just a number
273 my $cnt1 = $schema->resultset('TmpHoldsqueue')->count;
274 # Insert a new record in TmpHoldsqueue with that biblionumber
275 my $val = { biblionumber => $bibno };
276 my $rec = $builder->build({ source => 'TmpHoldsqueue', value => $val });
277 my $cnt2 = $schema->resultset('TmpHoldsqueue')->count;
278 is( defined($rec) && $cnt2 == $cnt1 + 1 , 1, 'Created a record' );
279 is( $builder->delete({ source => 'TmpHoldsqueue', records => $rec }),
280 undef, 'delete returns undef' );
281 is( $rec->{biblionumber}, $bibno, 'Hash value untouched' );
282 is( $schema->resultset('TmpHoldsqueue')->count, $cnt2,
283 "Method did not delete record in table without PK" );
285 # Test delete with NULL values
286 $val = { branchcode => undef };
287 is( $builder->delete({ source => 'Branch', records => $val }), 0,
288 'delete returns zero for an undef search with one key' );
289 $val = { module_bit => 1, #catalogue
290 code => undef };
291 is( $builder->delete({ source => 'Permission', records => $val }), 0,
292 'delete returns zero for an undef search with a composite PK' );
296 subtest 'Auto-increment values tests' => sub {
297 plan tests => 3;
299 # Pick a table with AI PK
300 my $source = 'Biblio'; # table
301 my $column = 'biblionumber'; # ai column
303 my $col_info = $schema->source( $source )->column_info( $column );
304 is( $col_info->{is_auto_increment}, 1, "biblio.biblionumber is detected as autoincrement");
306 # Create a biblio
307 my $biblio_1 = $builder->build({ source => $source });
308 # Get the AI value
309 my $ai_value = $biblio_1->{ biblionumber };
310 # Create a biblio
311 my $biblio_2 = $builder->build({ source => $source });
312 # Get the next AI value
313 my $next_ai_value = $biblio_2->{ biblionumber };
314 is( $ai_value + 1, $next_ai_value, "AI values are consecutive");
316 # respect autoincr column
317 warning_like { $builder->build({
318 source => $source,
319 value => { biblionumber => 123 },
320 }) } qr/^Value not allowed for auto_incr/,
321 'Build should not overwrite an auto_incr column';
324 subtest 'Date handling' => sub {
325 plan tests => 2;
327 $builder = t::lib::TestBuilder->new;
329 my $patron = $builder->build( { source => 'Borrower' } );
330 is( length( $patron->{updated_on} ), 19, 'A timestamp column value should be YYYY-MM-DD HH:MM:SS' );
331 is( length( $patron->{dateofbirth} ), 10, 'A date column value should be YYYY-MM-DD' );
335 $schema->storage->txn_rollback;