Bug 17736: Replace GetReservesFromBiblionumber with Koha::Biblio->holds
[koha.git] / t / db_dependent / UsageStats.t
1 # Copyright 2015 BibLibre
2 #
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation; either version 3 of the License, or (at your option) any later
8 # version.
9 #
10 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License along
15 # with Koha; if not, see <http://www.gnu.org/licenses>.
16
17 use Modern::Perl;
18 use Test::More tests => 57;
19 use t::lib::Mocks qw(mock_preference);
20 use POSIX qw(strftime);
21 use Data::Dumper;
22 use Koha::Biblios;
23
24 use Koha::Libraries;
25
26 BEGIN {
27     use_ok('C4::UsageStats');
28     use_ok('C4::Context');
29     use_ok('C4::Biblio');
30     use_ok( 'C4::AuthoritiesMarc', qw(AddAuthority) );
31     use_ok('C4::Reserves');
32     use_ok('MARC::Record');
33     use_ok('Koha::Acquisition::Order');
34 }
35
36 can_ok(
37     'C4::UsageStats', qw(
38       NeedUpdate
39       BuildReport
40       ReportToCommunity
41       _count )
42 );
43
44 my $dbh = C4::Context->dbh;
45 $dbh->{AutoCommit} = 0;
46 $dbh->{RaiseError} = 1;
47
48 $dbh->do('DELETE FROM issues');
49 $dbh->do('DELETE FROM biblio');
50 $dbh->do('DELETE FROM items');
51 $dbh->do('DELETE FROM auth_header');
52 $dbh->do('DELETE FROM old_issues');
53 $dbh->do('DELETE FROM old_reserves');
54 $dbh->do('DELETE FROM borrowers');
55 $dbh->do('DELETE FROM aqorders');
56 $dbh->do('DELETE FROM subscription');
57
58 #################################################
59 #             Testing Subs
60 #################################################
61
62 # ---------- Testing NeedUpdate -----------------
63
64 #Mocking C4::Context->preference("UsageStatsLastUpdateTime") to 0
65 my $now = strftime( "%s", localtime );
66 t::lib::Mocks::mock_preference( "UsageStatsLastUpdateTime", 0 );
67
68 my $update = C4::UsageStats->NeedUpdate;
69 is( $update, 1, "There is no last update, update needed" );
70
71 #Mocking C4::Context->preference("UsageStatsLastUpdateTime") to now
72 $now = strftime( "%s", localtime );
73 t::lib::Mocks::mock_preference( "UsageStatsLastUpdateTime", $now );
74
75 $update = C4::UsageStats->NeedUpdate;
76 is( $update, 0, "Last update just be done, no update needed " );
77
78 my $nb_of_libraries = Koha::Libraries->count;
79
80 # ---------- Testing BuildReport ----------------
81
82 #Test report->library -----------------
83 #mock to 0
84 t::lib::Mocks::mock_preference( "UsageStatsID",          0 );
85 t::lib::Mocks::mock_preference( "UsageStatsLibraryName", 0 );
86 t::lib::Mocks::mock_preference( "UsageStatsLibrariesInfo",  0 );
87 t::lib::Mocks::mock_preference( "UsageStatsLibraryType", 0 );
88 t::lib::Mocks::mock_preference( "UsageStatsCountry",     0 );
89 t::lib::Mocks::mock_preference( "UsageStatsLibraryUrl",  0 );
90
91 my $report = C4::UsageStats->BuildReport();
92
93 isa_ok( $report,              'HASH',  '$report is a HASH' );
94 isa_ok( $report->{libraries}, 'ARRAY', '$report->{libraries} is an ARRAY' );
95 is( scalar( @{ $report->{libraries} } ), 0, "There are 0 fields in libraries, libraries info are not shared" );
96 is( $report->{installation}->{koha_id}, 0,  "UsageStatsID          is good" );
97 is( $report->{installation}->{name},    '', "UsageStatsLibraryName is good" );
98 is( $report->{installation}->{url},     '', "UsageStatsLibraryUrl  is good" );
99 is( $report->{installation}->{type},    '', "UsageStatsLibraryType is good" );
100 is( $report->{installation}->{country}, '', "UsageStatsCountry     is good" );
101
102
103 #mock with values
104 t::lib::Mocks::mock_preference( "UsageStatsID",          1 );
105 t::lib::Mocks::mock_preference( "UsageStatsLibraryName", 'NAME' );
106 t::lib::Mocks::mock_preference( "UsageStatsLibraryUrl",  'URL' );
107 t::lib::Mocks::mock_preference( "UsageStatsLibraryType", 'TYPE' );
108 t::lib::Mocks::mock_preference( "UsageStatsCountry",     'COUNTRY' );
109 t::lib::Mocks::mock_preference( "UsageStatsLibrariesInfo", 1 );
110 t::lib::Mocks::mock_preference( "UsageStatsGeolocation", 1 );
111
112
113 $report = C4::UsageStats->BuildReport();
114
115 isa_ok( $report,              'HASH',  '$report is a HASH' );
116 isa_ok( $report->{libraries}, 'ARRAY', '$report->{libraries} is an ARRAY' );
117 is( scalar( @{ $report->{libraries} } ), $nb_of_libraries, "There are 6 fields in $report->{libraries}" );
118 is( $report->{installation}->{koha_id}, 1,     "UsageStatsID          is good" );
119 is( $report->{installation}->{name},   'NAME', "UsageStatsLibraryName is good" );
120 is( $report->{installation}->{url},     'URL', "UsageStatsLibraryUrl  is good" );
121 is( $report->{installation}->{type},   'TYPE', "UsageStatsLibraryType is good" );
122 is( $report->{installation}->{country}, 'COUNTRY', "UsageStatsCountry is good" );
123
124 #Test report->volumetry ---------------
125 #with original values
126 $report = C4::UsageStats->BuildReport();
127
128 isa_ok( $report,              'HASH', '$report is a HASH' );
129 isa_ok( $report->{volumetry}, 'HASH', '$report->{volumetry} is a HASH' );
130 is( scalar( keys %{$report->{volumetry}} ), 8, "There are 8 fields in $report->{volumetry}" );
131 is( $report->{volumetry}->{biblio},         0, "There is no biblio" );
132 is( $report->{volumetry}->{items},          0, "There is no items" );
133 is( $report->{volumetry}->{auth_header},    0, "There is no auth_header" );
134 is( $report->{volumetry}->{old_issues},     0, "There is no old_issues" );
135 is( $report->{volumetry}->{old_reserves},   0, "There is no old_reserves" );
136 is( $report->{volumetry}->{borrowers},      0, "There is no borrowers" );
137 is( $report->{volumetry}->{aqorders},       0, "There is no aqorders" );
138 is( $report->{volumetry}->{subscription},   0, "There is no subscription" );
139
140 #after adding objects
141 construct_objects_needed();
142
143 $report = C4::UsageStats->BuildReport();
144
145 isa_ok( $report,              'HASH', '$report is a HASH' );
146 isa_ok( $report->{volumetry}, 'HASH', '$report->{volumetry} is a HASH' );
147 is( scalar( keys %{$report->{volumetry}} ), 8, "There are 8 fields in $report->{volumetry}" );
148 is( $report->{volumetry}->{biblio},         3, "There are 3 biblio" );
149 is( $report->{volumetry}->{items},          3, "There are 3 items" );
150 is( $report->{volumetry}->{auth_header},    2, "There are 2 auth_header" );
151 is( $report->{volumetry}->{old_issues},     1, "There is  1 old_issues" );
152 is( $report->{volumetry}->{old_reserves},   1, "There is  1 old_reserves" );
153 is( $report->{volumetry}->{borrowers},      3, "There are 3 borrowers" );
154 is( $report->{volumetry}->{aqorders},       1, "There is  1 aqorders" );
155 is( $report->{volumetry}->{subscription},   1, "There is  1 subscription" );
156
157 #Test report->systempreferences -------
158 #mock to 0
159 mocking_systempreferences_to_a_set_value(0);
160
161 $report = C4::UsageStats->BuildReport();
162 isa_ok( $report,                      'HASH', '$report is a HASH' );
163 isa_ok( $report->{systempreferences}, 'HASH', '$report->{systempreferences} is a HASH' );
164 verif_systempreferences_values( $report, 0 );
165
166 #mock with values
167 mocking_systempreferences_to_a_set_value(1);
168
169 $report = C4::UsageStats->BuildReport();
170 isa_ok( $report,                      'HASH', '$report is a HASH' );
171 isa_ok( $report->{systempreferences}, 'HASH', '$report->{systempreferences} is a HASH' );
172 verif_systempreferences_values( $report, 1 );
173
174 #Test if unwanted syspref are not sent
175 is( $report->{systempreferences}->{useDischarge}, undef, 'useDischarge should not be shared');
176 is( $report->{systempreferences}->{OpacUserJS},   undef, 'OpacUserJS   should not be shared');
177
178 # ---------- Testing ReportToCommunity ----------
179
180 # ---------- Testing _count ---------------------
181 my $query = '
182   SELECT count(*)
183   FROM   borrowers
184   ';
185 my $count = $dbh->selectrow_array($query);
186
187 my $nb_fields = C4::UsageStats::_count('borrowers');
188 is( $nb_fields, $count, "_count return the good number of fields" );
189
190 #################################################
191 #             Subs
192 #################################################
193
194 # Adding :
195 # 3 borrowers
196 # 4 biblio
197 # 3 biblio items
198 # 3 items
199 # 2 auth_header
200 # 1 old_issues
201 # 1 old_reserves
202 # 1 subscription
203 # 1 aqorders
204 sub construct_objects_needed {
205
206     # ---------- 3 borrowers  ---------------------
207     my $surname1     = 'Borrower 1';
208     my $surname2     = 'Borrower 2';
209     my $surname3     = 'Borrower 3';
210     my $firstname1   = 'firstname 1';
211     my $firstname2   = 'firstname 2';
212     my $firstname3   = 'firstname 3';
213     my $cardnumber1  = 'test_card1';
214     my $cardnumber2  = 'test_card2';
215     my $cardnumber3  = 'test_card3';
216     my $categorycode = Koha::Database->new()->schema()->resultset('Category')->first()->categorycode();
217     my $branchcode   = Koha::Database->new()->schema()->resultset('Branch')->first()->branchcode();
218
219     my $query = '
220     INSERT INTO borrowers
221       (surname, firstname, cardnumber, branchcode, categorycode)
222     VALUES (?,?,?,?,?)';
223     my $insert_sth = $dbh->prepare($query);
224     $insert_sth->execute( $surname1, $firstname1, $cardnumber1, $branchcode, $categorycode );
225     my $borrowernumber1 = $dbh->last_insert_id( undef, undef, 'borrowers', undef );
226     $insert_sth->execute( $surname2, $firstname2, $cardnumber2, $branchcode, $categorycode );
227     my $borrowernumber2 = $dbh->last_insert_id( undef, undef, 'borrowers', undef );
228     $insert_sth->execute( $surname3, $firstname3, $cardnumber3, $branchcode, $categorycode );
229     my $borrowernumber3 = $dbh->last_insert_id( undef, undef, 'borrowers', undef );
230
231     # ---------- 3 biblios -----------------------
232     my $title1  = 'Title 1';
233     my $title2  = 'Title 2';
234     my $title3  = 'Title 3';
235     my $author1 = 'Author 1';
236     my $author2 = 'Author 2';
237     my $author3 = 'Author 3';
238
239     $query = '
240     INSERT INTO biblio
241       (title, author)
242     VALUES (?,?)';
243     $insert_sth = $dbh->prepare($query);
244     $insert_sth->execute( $title1, $author1 );
245     my $biblionumber1 = $dbh->last_insert_id( undef, undef, 'biblio', undef );
246     $insert_sth->execute( $title2, undef );
247     my $biblionumber2 = $dbh->last_insert_id( undef, undef, 'biblio', undef );
248     $insert_sth->execute( $title3, $author3 );
249     my $biblionumber3 = $dbh->last_insert_id( undef, undef, 'biblio', undef );
250
251     # ---------- 3 biblio items  -------------------------
252     $query = '
253     INSERT INTO biblioitems
254       (biblionumber, itemtype)
255     VALUES (?,?)';
256     $insert_sth = $dbh->prepare($query);
257     $insert_sth->execute( $biblionumber1, 'Book' );
258     my $biblioitemnumber1 = $dbh->last_insert_id( undef, undef, 'biblioitems', undef );
259     $insert_sth->execute( $biblionumber2, 'Music' );
260     my $biblioitemnumber2 = $dbh->last_insert_id( undef, undef, 'biblioitems', undef );
261     $insert_sth->execute( $biblionumber3, 'Book' );
262     my $biblioitemnumber3 = $dbh->last_insert_id( undef, undef, 'biblioitems', undef );
263
264     # ---------- 3 items  -------------------------
265     my $barcode1 = '111111';
266     my $barcode2 = '222222';
267     my $barcode3 = '333333';
268
269     $query = '
270     INSERT INTO items
271       (biblionumber, biblioitemnumber, barcode, itype)
272     VALUES (?,?,?,?)';
273     $insert_sth = $dbh->prepare($query);
274     $insert_sth->execute( $biblionumber1, $biblioitemnumber1, $barcode1, 'Book' );
275     my $item_number1 = $dbh->last_insert_id( undef, undef, 'items', undef );
276     $insert_sth->execute( $biblionumber2, $biblioitemnumber2, $barcode2, 'Music' );
277     my $item_number2 = $dbh->last_insert_id( undef, undef, 'items', undef );
278     $insert_sth->execute( $biblionumber3, $biblioitemnumber3, $barcode3, 'Book' );
279     my $item_number3 = $dbh->last_insert_id( undef, undef, 'items', undef );
280
281     # ---------- Add 2 auth_header
282     $query = '
283     INSERT INTO auth_header
284       (authtypecode)
285     VALUES (?)';
286     $insert_sth = $dbh->prepare($query);
287     $insert_sth->execute('authtypecode1');
288     my $authid1 = $dbh->last_insert_id( undef, undef, 'auth_header', undef );
289     $insert_sth->execute('authtypecode2');
290     my $authid2 = $dbh->last_insert_id( undef, undef, 'auth_header', undef );
291
292     # ---------- Add 1 old_issues
293     $query = '
294     INSERT INTO old_issues
295       (borrowernumber, branchcode, itemnumber)
296     VALUES (?,?,?)';
297     $insert_sth = $dbh->prepare($query);
298     $insert_sth->execute( $borrowernumber1, $branchcode, $item_number1 );
299     my $issue_id1 = $dbh->last_insert_id( undef, undef, 'old_issues', undef );
300
301     # ---------- Add 1 old_reserves
302     AddReserve( $branchcode, $borrowernumber1, $biblionumber1, '', 1, undef, undef, '', 'Title', undef, undef );
303     my $biblio = Koha::Biblios->find( $biblionumber1 );
304     my $holds = $biblio->holds;
305     CancelReserve( { reserve_id => $holds->next->reserve_id } );
306
307     # ---------- Add 1 aqbudgets
308     $query = '
309     INSERT INTO aqbudgets
310       (budget_amount)
311     VALUES (?)';
312     $insert_sth = $dbh->prepare($query);
313     $insert_sth->execute("20.0");
314     my $aqbudgets1 = $dbh->last_insert_id( undef, undef, 'aqbudgets', undef );
315
316     # ---------- Add 1 aqorders
317     $query = '
318     INSERT INTO aqorders
319       (budget_id, basketno, biblionumber, invoiceid, subscriptionid)
320     VALUES (?,?,?,?,?)';
321     $insert_sth = $dbh->prepare($query);
322     $insert_sth->execute( $aqbudgets1, undef, undef, undef, undef );
323     my $aqorders1 = $dbh->last_insert_id( undef, undef, 'aqorders', undef );
324
325     # --------- Add 1 subscription
326     $query = '
327     INSERT INTO subscription
328       (biblionumber)
329     VALUES (?)';
330     $insert_sth = $dbh->prepare($query);
331     $insert_sth->execute($biblionumber1);
332     my $subscription1 = $dbh->last_insert_id( undef, undef, 'subscription', undef );
333
334 }
335
336 #Change systempreferences values to $set_value
337 sub mocking_systempreferences_to_a_set_value {
338     my $set_value = shift;
339
340     foreach (
341         qw/
342         AcqCreateItem
343         AcqWarnOnDuplicateInvoice
344         AcqViewBaskets
345         BasketConfirmations
346         OrderPdfFormat
347         casAuthentication
348         casLogout
349         AllowPKIAuth
350         DebugLevel
351         delimiter
352         noItemTypeImages
353         virtualshelves
354         AutoLocation
355         IndependentBranches
356         SessionStorage
357         Persona
358         AuthDisplayHierarchy
359         AutoCreateAuthorities
360         BiblioAddsAuthorities
361         dontmerge
362         UseAuthoritiesForTracings
363         CatalogModuleRelink
364         hide_marc
365         IntranetBiblioDefaultView
366         LabelMARCView
367         OpacSuppression
368         SeparateHoldings
369         UseControlNumber
370         advancedMARCeditor
371         DefaultClassificationSource
372         EasyAnalyticalRecords
373         autoBarcode
374         item-level_itypes
375         marcflavour
376         PrefillItem
377         z3950NormalizeAuthor
378         SpineLabelAutoPrint
379         SpineLabelShowPrintOnBibDetails
380         BlockReturnOfWithdrawnItems
381         CalculateFinesOnReturn
382         AgeRestrictionOverride
383         AllFinesNeedOverride
384         AllowFineOverride
385         AllowItemsOnHoldCheckout
386         AllowItemsOnHoldCheckoutSCO
387         AllowNotForLoanOverride
388         AllowRenewalLimitOverride
389         AllowReturnToBranch
390         AllowTooManyOverride
391         AutomaticItemReturn
392         AutoRemoveOverduesRestrictions
393         CircControl
394         HomeOrHoldingBranch
395         HomeOrHoldingBranchReturn
396         InProcessingToShelvingCart
397         IssueLostItem
398         IssuingInProcess
399         ManInvInNoissuesCharge
400         OverduesBlockCirc
401         RenewalPeriodBase
402         RenewalSendNotice
403         RentalsInNoissuesCharge
404         ReturnBeforeExpiry
405         ReturnToShelvingCart
406         TransfersMaxDaysWarning
407         UseBranchTransferLimits
408         useDaysMode
409         UseTransportCostMatrix
410         UseCourseReserves
411         finesCalendar
412         FinesIncludeGracePeriod
413         finesMode
414         RefundLostOnReturnControl
415         WhenLostChargeReplacementFee
416         WhenLostForgiveFine
417         AllowHoldDateInFuture
418         AllowHoldPolicyOverride
419         AllowHoldsOnDamagedItems
420         AllowHoldsOnPatronsPossessions
421         AutoResumeSuspendedHolds
422         canreservefromotherbranches
423         decreaseLoanHighHolds
424         DisplayMultiPlaceHold
425         emailLibrarianWhenHoldIsPlaced
426         ExpireReservesMaxPickUpDelay
427         OPACAllowHoldDateInFuture
428         OPACAllowUserToChooseBranch
429         ReservesControlBranch
430         ReservesNeedReturns
431         SuspendHoldsIntranet
432         SuspendHoldsOpac
433         TransferWhenCancelAllWaitingHolds
434         AllowAllMessageDeletion
435         AllowOfflineCirculation
436         CircAutocompl
437         CircAutoPrintQuickSlip
438         DisplayClearScreenButton
439         FilterBeforeOverdueReport
440         FineNotifyAtCheckin
441         itemBarcodeFallbackSearch
442         itemBarcodeInputFilter
443         previousIssuesDefaultSortOrder
444         RecordLocalUseOnReturn
445         soundon
446         SpecifyDueDate
447         todaysIssuesDefaultSortOrder
448         UpdateTotalIssuesOnCirc
449         UseTablesortForCirc
450         WaitingNotifyAtCheckin
451         AllowSelfCheckReturns
452         AutoSelfCheckAllowed
453         FRBRizeEditions
454         OPACFRBRizeEditions
455         AmazonCoverImages
456         OPACAmazonCoverImages
457         Babeltheque
458         BakerTaylorEnabled
459         GoogleJackets
460         HTML5MediaEnabled
461         IDreamBooksReadometer
462         IDreamBooksResults
463         IDreamBooksReviews
464         LibraryThingForLibrariesEnabled
465         LocalCoverImages
466         OPACLocalCoverImages
467         NovelistSelectEnabled
468         XISBN
469         OpenLibraryCovers
470         OpenLibrarySearch
471         UseKohaPlugins
472         SyndeticsEnabled
473         TagsEnabled
474         CalendarFirstDayOfWeek
475         opaclanguagesdisplay
476         AuthoritiesLog
477         BorrowersLog
478         CataloguingLog
479         FinesLog
480         IssueLog
481         LetterLog
482         ReturnLog
483         SubscriptionLog
484         BiblioDefaultView
485         COinSinOPACResults
486         DisplayOPACiconsXSLT
487         hidelostitems
488         HighlightOwnItemsOnOPAC
489         OpacAddMastheadLibraryPulldown
490         OPACDisplay856uAsImage
491         OpacHighlightedWords
492         OpacKohaUrl
493         OpacMaintenance
494         OpacPublic
495         OpacSeparateHoldings
496         OPACShowBarcode
497         OPACShowCheckoutName
498         OpacShowFiltersPulldownMobile
499         OPACShowHoldQueueDetails
500         OpacShowLibrariesPulldownMobile
501         OpacShowRecentComments
502         OPACShowUnusedAuthorities
503         OpacStarRatings
504         opacthemes
505         OPACURLOpenInNewWindow
506         OpacAuthorities
507         opacbookbag
508         OpacBrowser
509         OpacBrowseResults
510         OpacCloud
511         OPACFinesTab
512         OpacHoldNotes
513         OpacItemLocation
514         OpacPasswordChange
515         OPACPatronDetails
516         OPACpatronimages
517         OPACPopupAuthorsSearch
518         OpacTopissue
519         opacuserlogin
520         QuoteOfTheDay
521         RequestOnOpac
522         reviewson
523         ShowReviewer
524         ShowReviewerPhoto
525         SocialNetworks
526         suggestion
527         AllowPurchaseSuggestionBranchChoice
528         OpacAllowPublicListCreation
529         OpacAllowSharingPrivateLists
530         OpacRenewalAllowed
531         OpacRenewalBranch
532         OPACViewOthersSuggestions
533         SearchMyLibraryFirst
534         singleBranchMode
535         AnonSuggestions
536         EnableOpacSearchHistory
537         OPACPrivacy
538         opacreadinghistory
539         TrackClicks
540         PatronSelfRegistration
541         OPACShelfBrowser
542         AutoEmailOpacUser
543         AutoEmailPrimaryAddress
544         autoMemberNum
545         BorrowerRenewalPeriodBase
546         checkdigit
547         EnableBorrowerFiles
548         EnhancedMessagingPreferences
549         ExtendedPatronAttributes
550         intranetreadinghistory
551         memberofinstitution
552         patronimages
553         TalkingTechItivaPhoneNotification
554         uppercasesurnames
555         IncludeSeeFromInSearches
556         OpacGroupResults
557         QueryAutoTruncate
558         QueryFuzzy
559         QueryStemming
560         QueryWeightFields
561         TraceCompleteSubfields
562         TraceSubjectSubdivisions
563         UseICU
564         UseQueryParser
565         defaultSortField
566         displayFacetCount
567         OPACdefaultSortField
568         OPACItemsResultsDisplay
569         expandedSearchOption
570         IntranetNumbersPreferPhrase
571         OPACNumbersPreferPhrase
572         opacSerialDefaultTab
573         RenewSerialAddsSuggestion
574         RoutingListAddReserves
575         RoutingSerials
576         SubscriptionHistory
577         Display856uAsImage
578         DisplayIconsXSLT
579         template
580         yuipath
581         HidePatronName
582         intranetbookbag
583         StaffDetailItemSelection
584         viewISBD
585         viewLabeledMARC
586         viewMARC
587         ILS-DI
588         OAI-PMH
589         version
590         AudioAlerts
591         /
592       ) {
593         t::lib::Mocks::mock_preference( $_, $set_value );
594     }
595 }
596
597 #Test if all systempreferences are at $value_to_test
598 sub verif_systempreferences_values {
599     my ( $report, $value_to_test ) = @_;
600
601     my @missings;
602     foreach my $key ( keys %{$report->{systempreferences}} ) {
603         if ( $report->{systempreferences}->{$key} ne $value_to_test ) {
604             warn $key;
605             push @missings, $key;
606         }
607     }
608     unless ( @missings ) {
609         ok(1, 'All prefs are present');
610     } else {
611         ok(0, 'Some prefs are missing: ' . Dumper(\@missings));
612     }
613 }
614
615 $dbh->rollback;