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