staging import - enhance record overlay behavior
[koha.git] / t / lib / KohaTest.pm
1 package KohaTest;
2 use base qw(Test::Class);
3
4 use Test::More;
5 use Data::Dumper;
6
7 eval "use Test::Class";
8 plan skip_all => "Test::Class required for performing database tests" if $@;
9 # Or, maybe I should just die there.
10
11 use C4::Biblio;
12 use C4::Bookfund;
13 use C4::Bookseller;
14 use C4::Context;
15 use C4::Items;
16 use C4::Members;
17 use C4::Search;
18 use File::Temp qw/ tempdir /;
19
20 # Since this is an abstract base class, this prevents these tests from
21 # being run directly unless we're testing a subclass. It just makes
22 # things faster.
23 __PACKAGE__->SKIP_CLASS( 1 );
24
25
26 =head2 startup methods
27
28 these are run once, at the beginning of the whole test suite
29
30 =cut
31
32 sub startup_15_truncate_tables : Test( startup => 1 ) {
33     my $self = shift;
34     
35 #     my @truncate_tables = qw( accountlines 
36 #                               accountoffsets              
37 #                               action_logs                 
38 #                               alert                       
39 #                               aqbasket                    
40 #                               aqbookfund                  
41 #                               aqbooksellers               
42 #                               aqbudget                    
43 #                               aqorderbreakdown            
44 #                               aqorderdelivery             
45 #                               aqorders                    
46 #                               auth_header                 
47 #                               auth_subfield_structure     
48 #                               auth_tag_structure          
49 #                               auth_types                  
50 #                               authorised_values           
51 #                               biblio                      
52 #                               biblio_framework            
53 #                               biblioitems                 
54 #                               borrowers                   
55 #                               branchcategories            
56 #                               branches                    
57 #                               branchrelations             
58 #                               branchtransfers             
59 #                               browser                     
60 #                               categories                  
61 #                               categorytable               
62 #                               cities                      
63 #                               class_sort_rules            
64 #                               class_sources               
65 #                               currency                    
66 #                               deletedbiblio               
67 #                               deletedbiblioitems          
68 #                               deletedborrowers            
69 #                               deleteditems                
70 #                               ethnicity                   
71 #                               import_batches              
72 #                               import_biblios              
73 #                               import_items                
74 #                               import_record_matches       
75 #                               import_records              
76 #                               issues                      
77 #                               issuingrules                
78 #                               items                       
79 #                               itemtypes                   
80 #                               labels                      
81 #                               labels_conf                 
82 #                               labels_profile              
83 #                               labels_templates            
84 #                               language_descriptions       
85 #                               language_rfc4646_to_iso639  
86 #                               language_script_bidi        
87 #                               language_script_mapping     
88 #                               language_subtag_registry    
89 #                               letter                      
90 #                               marc_matchers               
91 #                               marc_subfield_structure     
92 #                               marc_tag_structure          
93 #                               matchchecks                 
94 #                               matcher_matchpoints         
95 #                               matchpoint_component_norms  
96 #                               matchpoint_components       
97 #                               matchpoints                 
98 #                               mediatypetable              
99 #                               notifys                     
100 #                               nozebra                     
101 #                               old_issues                  
102 #                               old_reserves                
103 #                               opac_news                   
104 #                               overduerules                
105 #                               patroncards                 
106 #                               patronimage                 
107 #                               printers                    
108 #                               printers_profile            
109 #                               repeatable_holidays         
110 #                               reports_dictionary          
111 #                               reserveconstraints          
112 #                               reserves                    
113 #                               reviews                     
114 #                               roadtype                    
115 #                               saved_reports               
116 #                               saved_sql                   
117 #                               serial                      
118 #                               serialitems                 
119 #                               services_throttle           
120 #                               sessions                    
121 #                               special_holidays            
122 #                               statistics                  
123 #                               stopwords                   
124 #                               subcategorytable            
125 #                               subscription                
126 #                               subscriptionhistory         
127 #                               subscriptionroutinglist     
128 #                               suggestions                 
129 #                               systempreferences           
130 #                               tags                        
131 #                               userflags                   
132 #                               virtualshelfcontents        
133 #                               virtualshelves              
134 #                               z3950servers                
135 #                               zebraqueue                  
136 #                         );
137
138     my @truncate_tables = qw( accountlines 
139                               accountoffsets              
140                               alert                       
141                               aqbasket                    
142                               aqbooksellers               
143                               aqorderbreakdown            
144                               aqorderdelivery             
145                               aqorders                    
146                               auth_header                 
147                               branchcategories            
148                               branchrelations             
149                               branchtransfers             
150                               browser                     
151                               categorytable               
152                               cities                      
153                               deletedbiblio               
154                               deletedbiblioitems          
155                               deletedborrowers            
156                               deleteditems                
157                               ethnicity                   
158                               issues                      
159                               issuingrules                
160                               labels                      
161                               labels_profile              
162                               matchchecks                 
163                               mediatypetable              
164                               notifys                     
165                               nozebra                     
166                               old_issues                  
167                               old_reserves                
168                               overduerules                
169                               patroncards                 
170                               patronimage                 
171                               printers                    
172                               printers_profile            
173                               reports_dictionary          
174                               reserveconstraints          
175                               reserves                    
176                               reviews                     
177                               roadtype                    
178                               saved_reports               
179                               saved_sql                   
180                               serial                      
181                               serialitems                 
182                               services_throttle           
183                               special_holidays            
184                               statistics                  
185                               subcategorytable            
186                               subscription                
187                               subscriptionhistory         
188                               subscriptionroutinglist     
189                               suggestions                 
190                               tags                        
191                               virtualshelfcontents        
192                         );
193     
194     my $failed_to_truncate = 0;
195     foreach my $table ( @truncate_tables ) {
196         my $dbh = C4::Context->dbh();
197         $dbh->do( "truncate $table" )
198           or $failed_to_truncate = 1;
199     }
200     is( $failed_to_truncate, 0, 'truncated tables' );
201     
202 }
203
204 =head2 startup_20_add_bookseller
205
206 we need a bookseller for many of the tests, so let's insert one. Feel
207 free to use this one, or insert your own.
208
209 =cut
210
211 sub startup_20_add_bookseller : Test(startup => 1) {
212     my $self = shift;
213
214     my $booksellerinfo = { name => 'bookseller ' . $self->random_string(),
215                       };
216
217     my $id = AddBookseller( $booksellerinfo );
218     ok( $id, "created bookseller: $id" );
219     $self->{'booksellerid'} = $id;
220     
221     return;
222 }
223
224 =head2 startup_22_add_bookfund
225
226 we need a bookfund for many of the tests. This currently uses one that
227 is in the skeleton database.  free to use this one, or insert your
228 own.
229
230 =cut
231
232 sub startup_22_add_bookfund : Test(startup => 2) {
233     my $self = shift;
234
235     my $bookfundid = 'GEN';
236     my $bookfund = GetBookFund( $bookfundid, undef );
237     # diag( Data::Dumper->Dump( [ $bookfund ], qw( bookfund  ) ) );
238     is( $bookfund->{'bookfundid'},   $bookfundid,      "found bookfund: '$bookfundid'" );
239     is( $bookfund->{'bookfundname'}, 'General Stacks', "found bookfund: '$bookfundid'" );
240     
241     $self->{'bookfundid'} = $bookfundid;
242     return;
243 }
244
245 =head2 startup_24_add_member
246
247 Add a patron/member for the tests to use
248
249 =cut
250
251 sub startup_24_add_member : Test(startup => 1) {
252     my $self = shift;
253
254     my $memberinfo = { surname      => 'surname '  . $self->random_string(),
255                        firstname    => 'firstname' . $self->random_string(),
256                        address      => 'address'   . $self->random_string(),
257                        city         => 'city'      . $self->random_string(),
258                        branchcode   => 'CPL', # CPL => Centerville
259                        categorycode => 'PT',  # PT  => PaTron
260                   };
261
262     my $id = AddMember( %$memberinfo );
263     ok( $id, "created member: $id" );
264     $self->{'memberid'} = $id;
265     
266     return;
267 }
268
269 =head2 setup methods
270
271 setup methods are run before every test method
272
273 =cut
274
275 =head2 teardown methods
276
277 teardown methods are many time, once at the end of each test method.
278
279 =cut
280
281 =head2 shutdown methods
282
283 shutdown methods are run once, at the end of the test suite
284
285 =cut
286
287 =head2 utility methods
288
289 These are not test methods, but they're handy
290
291 =cut
292
293 =head3 random_string
294
295 Nice for generating names and such. It's not actually random, more
296 like arbitrary.
297
298 =cut
299
300 sub random_string {
301     my $self = shift;
302
303     my $wordsize = 6;  # how many letters in your string?
304
305     # leave out these characters: "oOlL10". They're too confusing.
306     my @alphabet = ( 'a'..'k','m','n','p'..'z', 'A'..'K','M','N','P'..'Z', 2..9 );
307
308     my $randomstring;
309     foreach ( 0..$wordsize ) {
310         $randomstring .= $alphabet[ rand( scalar( @alphabet ) ) ];
311     }
312     return $randomstring;
313     
314 }
315
316 =head3 add_biblios
317
318   $self->add_biblios( count     => 10,
319                       add_items => 1, );
320
321   named parameters:
322      count: number of biblios to add
323      add_items: should you add items for each one?
324
325   returns:
326     I don't know yet.
327
328   side effects:
329     adds the biblionumbers to the $self->{'biblios'} listref
330
331   Notes:
332     Should I allow you to pass in biblio information, like title?
333     Since this method is in the KohaTest class, all tests in it will be ignored, unless you call this from your own namespace.
334     This runs 10 tests, plus 4 for each "count", plus 3 more for each item added.
335
336 =cut
337
338 sub add_biblios {
339     my $self = shift;
340     my %param = @_;
341
342     $param{'count'}     = 1 unless defined( $param{'count'} );
343     $param{'add_items'} = 0 unless defined( $param{'add_items'} );
344
345     foreach my $counter ( 1..$param{'count'} ) {
346         my $marcrecord  = MARC::Record->new();
347         isa_ok( $marcrecord, 'MARC::Record' );
348         my $appendedfieldscount = $marcrecord->append_fields( MARC::Field->new( '100', '1', '0',
349                                                                                 a => 'Twain, Mark',
350                                                                                 d => "1835-1910." ),
351                                                               MARC::Field->new( '245', '1', '4',
352                                                                                 a => sprintf( 'The Adventures of Huckleberry Finn Test %s', $counter ),
353                                                                                 c => "Mark Twain ; illustrated by E.W. Kemble." )
354                                                          );
355         is( $appendedfieldscount, 2, 'added 2 fields' );
356         
357         my $frameworkcode = ''; # XXX I'd like to put something reasonable here.
358         my ( $biblionumber, $biblioitemnumber ) = AddBiblio( $marcrecord, $frameworkcode );
359         ok( $biblionumber, "the biblionumber is $biblionumber" );
360         ok( $biblioitemnumber, "the biblioitemnumber is $biblioitemnumber" );
361         if ( $param{'add_items'} ) {
362             # my @iteminfo = AddItem( {}, $biblionumber );
363             my @iteminfo = AddItemFromMarc( $marcrecord, $biblionumber );
364             is( $iteminfo[0], $biblionumber,     "biblionumber is $biblionumber" );
365             is( $iteminfo[1], $biblioitemnumber, "biblioitemnumber is $biblioitemnumber" );
366             ok( $iteminfo[2], "itemnumber is $iteminfo[2]" );
367         }
368         push @{$self->{'biblios'}}, $biblionumber;
369     }
370     
371     my $query = 'Finn Test';
372
373     # XXX we're going to repeatedly try to fetch the marc records that
374     # we inserted above. It may take a while before they all show
375     # up. why?
376     my $tries = 30;
377     DELAY: foreach my $trial ( 1..$tries ) {
378         diag "waiting for zebra indexing. Trial: $trial of $tries";
379         my ( $error, $results ) = SimpleSearch( $query );
380         if ( $param{'count'} <= scalar( @$results ) ) {
381             ok( $tries, "found all $param{'count'} titles after $trial tries" );
382             last DELAY;
383         }
384         sleep( 3 );
385     } continue {
386         if ( $trial == $tries ) {
387             fail( "we never found all $param{'count'} titles even after $tries tries." );
388         }
389     }
390
391     
392 }
393
394 =head3 reindex_bibs
395
396 Do a fast reindexing of all of the bib and authority
397 records and mark all zebraqueue entries done.
398
399 Useful for test routines that need to do a
400 lot of indexing without having to wait for
401 zebraqueue.
402
403 In NoZebra model, this only marks zebraqueue
404 done - the records should already be indexed.
405
406 =cut
407
408 sub reindex_marc {
409     my $self = shift;
410
411     # mark zebraqueue done regardless of the indexing mode
412     my $dbh = C4::Context->dbh();
413     $dbh->do("UPDATE zebraqueue SET done = 1 WHERE done = 0");
414
415     return if C4::Context->preference('NoZebra');
416
417     my $directory = tempdir(CLEANUP => 1);
418     foreach my $record_type qw(biblio authority) {
419         mkdir "$directory/$record_type";
420         my $sth = $dbh->prepare($record_type eq "biblio" ? "SELECT marc FROM biblioitems" : "SELECT marc FROM auth_header");
421         $sth->execute();
422         open OUT, ">:utf8", "$directory/$record_type/records";
423         while (my ($blob) = $sth->fetchrow_array) {
424             print OUT $blob;
425         }
426         close OUT;
427         my $zebra_server = "${record_type}server";
428         my $zebra_config  = C4::Context->zebraconfig($zebra_server)->{'config'};
429         my $zebra_db_dir  = C4::Context->zebraconfig($zebra_server)->{'directory'};
430         my $zebra_db = $record_type eq 'biblio' ? 'biblios' : 'authorities';
431         system "zebraidx -c $zebra_config -d $zebra_db -g iso2709 init > /dev/null 2>\&1";
432         system "zebraidx -c $zebra_config -d $zebra_db -g iso2709 update $directory/${record_type} > /dev/null 2>\&1";
433         system "zebraidx -c $zebra_config -d $zebra_db -g iso2709 commit > /dev/null 2>\&1";
434     }
435         
436 }
437
438 1;