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