Koha/t
Marcel de Rooy 99672d1f00 Bug 16155: Composite keys in TestBuilder and more
The number of tests using TestBuilder is gradually growing. Once you
are familiar with its use, you will appreciate it and find yourself
using it when writing new tests. Although it works quite well, some details
still needs some polishing.

While looking at the handling of composite keys in TestBuilder, a number
of related points came up too. This patch finally ended up in setting
the following design goals:

[1] TB should not only look at the first column of a composite FK.
[2] TB should optionally create records for fixed FK values.
[3] TB should create a new record, never change an existing record.
[4] TB should respect auto_increment columns.
[5] Passing a hash for a foreign key should always imply a new record.
[6] Explicitly passing undef for a column should mean NULL.
[7] Add a delete method; it will replace the clear method.
[8] Simplify by removing $default_values, hash key _fk and param only_fk.

The comments below further clarify these points. Note that they refer to
the old behavior (before this patch) unless stated otherwise.

Comments for point 1
====================
Look at:
    $builder->build({
        source => 'UserPermission',
        value => {
            borrowernumber => $borrowerno,
            module_bit => { flag => 'my flag' },
            code => 'will_be_ignored',
        },
    });
Module_bit and code here are a composite FK to permissions.
TB ignores the value for the code column here and creates a record with a
randomized code.

But if we would pass the hash in the second column of this compound key like:
            borrowernumber => $borrowerno,
            module_bit => 10,
            code => { code => 'new_code' },
TB would now crash when passing the hash for code thru to DBIx.

Comments for point 2
====================
Look at:
    $builder->build({
        source => 'UserPermission',
        value => {
            borrowernumber => $borrowerno,
            module_bit => 99,
            code => 'new_super_tool',
        },
    });
TB detects a fixed value for the module_bit, continues and will crash on
DBIx if the foreign keys are not found. In this case it would be friendly
to create a missing linked record.

Comments for point 3
====================
Look at:
    $builder->build({
        source => 'Branch',
        value  => { branchcode => 'CPL' },
    });
If this branch already exists, this call would modify the branch record and
overwrite all columns with randomized values (expected or not). In any case,
it would be safer here to return undef than modifying an existing record.

Comments for point 4
====================
Look at:
    $builder->build({
        source => 'Borrower',
        value  => { borrowernumber => '123456789' },
    });
If this number would exist, we would update (as earlier). But if this
number does not exist, we would create the record. Although that is
technically possible, I would prefer to have TB respect the auto
increment property of this column.

Comments for point 5
====================
Look at:
    $builder->build({
        source => 'Item',
        value  => { homebranch => { branchcode => 'MPL' } },
    });
As discussed under point 3, we should actually not pass primary key values
if we expect to build new records. The same also holds for the deeper
(recursive) calls to build when using hashes like here for homebranch.
In this case again an existing record might be overwritten.

Comments for point 6
====================
Look at:
    $builder->build({
        source => 'Reserve',
        value => { itemnumber => undef },
    });
As you know, a reserve without an itemnumber is a biblio level hold.
Unfortunately, TB did not care about passing undefs until now. So you would
get an item level hold.
In the new situation TB will respect these explicit undefs, as long as the
corresponding foreign key column is nullable of course.

Comments for point 7
====================
This patch will allow you to delete records created by TB:
    my $patron = $builder->build({ source => 'Borrower' });
    $builder->delete({ source => 'Borrower', records => $patron });
Or:
    $builder->delete({ source => 'Borrower', records => [ $patron, ... ] });
For safety, delete requires you to provide all primary key values in the
passed hashref(s).
Deleting all records in a table via clear is no longer supported and can
still be arranged in one statement.

Comments for point 8
====================
Current use of TestBuilder reveals that $default_values and only_fk
are not really needed. The current $default_values should imo not be in the
module anyway; if you want to use it, you could still pass it to TB:
    $builder->build({ ..., value => { %defa, %your_values } });

Only_fk stops at the very last step of saving the top level record while
storing all linked records at the lower levels. Practical use is not
very obvious; it can be easily simulated by one delete statement.

The hash key _fk is now used to store all linked records one or more levels
down. It is used in a few tests to retrieve a value one level down.
Why not retrieve that one value via the database and get rid of the
whole structure?

Implementation
==============
This highlights the main changes:

The $default_value hash (with some hardcoded values for UserPermission)
is removed from the module. It was used by a test in TestBuilder.t and has
been relocated.
The value of $gen_type is returned now by sub _gen_type. (See new.)

The main change in the build method is moving the foreign keys logic to a
new subroutine _create_links. This routine now looks at all columns of a
composite FK. It checks if a linked record exists for passed values, and
it looks at NULL values.

Routine _buildColumnValues is slightly adjusted to allow for passed undef
values. The theoretically endless loop is replaced by three tries. For
composite unique constraints we only check complete sets of values.

Routine _getForeignKeys contains a check to not return the same relation
twice in case of doubled belongs_to relations in the DBIx scheme.

The eval in _storeColumnValues is removed. The autoincrement check in sub
_buildColumnValue got more priority; the handling of foreign keys has been
adjusted and a check for not-nullable columns has been added.

TEST PLAN
=========
This patch only deals with the TestBuilder module itself. In the follow-up
patches TestBuilder.t and a few other unit tests are adjusted.

[1] Do not yet apply this patch. But apply the 'OldBehavior' patch.
    Verify that all tests pass. (They cover the first six design goals.)
[2] Apply this patch. Does TestBuilder still compile (perl -c)?
[3] Run the OldBehavior test again. Do all tests fail now? This means
    that we got rid of all unwanted side-effects in the list of goals.
[4] Run some other tests that use TestBuilder. (See below.)
    Skip the following tests; a follow-up patch deals with them.
    t/db_dependent/Accounts.t
    t/db_dependent/Barcodes.t
    t/db_dependent/Circulation/AnonymiseIssueHistory.t
    t/db_dependent/Circulation/CalcFine.t
    t/db_dependent/Holds.t
    t/db_dependent/Items/MoveItemFromBiblio.t
    t/db_dependent/Koha/BiblioFrameworks.t
    t/db_dependent/Members.t
    t/db_dependent/TestBuilder.t

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
The following tests pass:
    t/db_dependent/Acquisition/OrderUsers.t
    t/db_dependent/Auth/haspermission.t
    t/db_dependent/Barcodes_ValueBuilder.t
    t/db_dependent/Budgets.t
    t/db_dependent/Category.t
    t/db_dependent/Circulation.t
    t/db_dependent/Circulation/GetTopIssues.t
    t/db_dependent/Circulation/IsItemIssued.t
    t/db_dependent/Circulation/IssuingRules/maxsuspensiondays.t
    t/db_dependent/Circulation/Returns.t
    t/db_dependent/Circulation/TooMany.t
    t/db_dependent/Circulation_dateexpiry.t
    t/db_dependent/Circulation_transfers.t
    t/db_dependent/CourseReserves.t
    t/db_dependent/Creators/Lib.t
    t/db_dependent/DecreaseLoanHighHolds.t
    t/db_dependent/Exporter/Record.t
    t/db_dependent/Holds/LocalHoldsPriority.t
    t/db_dependent/Holds/RevertWaitingStatus.t:
    t/db_dependent/HoldsQueue.t
    t/db_dependent/Holidays.t
    t/db_dependent/Items.t
    t/db_dependent/Items_DelItem.t
    t/db_dependent/Koha/Acquisition/Currencies.t
    t/db_dependent/Koha/Authorities.t
    t/db_dependent/Koha/BiblioFrameworks.t
    t/db_dependent/Koha/Cities.t
    t/db_dependent/Koha/Libraries.t
    t/db_dependent/Koha/Objects.t
    t/db_dependent/Koha/Patron/Categories.t
    t/db_dependent/Koha/Patron/Images.t
    t/db_dependent/Koha/Patron/Messages.t
    t/db_dependent/Koha/Patrons.t
    t/db_dependent/Koha/SMS_Providers.t
    t/db_dependent/Koha_template_plugin_Branches.t
    t/db_dependent/Letters.t
    t/db_dependent/Members/AddEnrolmentFeeIfNeeded.t
    t/db_dependent/Members/GetUpcomingMembershipExpires.t
    t/db_dependent/Members_Attributes.t
    t/db_dependent/Patron/Borrower_Debarments.t
    t/db_dependent/Patron/Borrower_Discharge.t
    t/db_dependent/Patron/Borrower_Files.t
    t/db_dependent/Ratings.t
    t/db_dependent/Reports_Guided.t
    t/db_dependent/Reserves/GetReserveFee.t
    t/db_dependent/Review.t
    t/db_dependent/Serials_2.t
    t/db_dependent/ShelfBrowser.t
    t/db_dependent/Virtualshelves.t
    t/db_dependent/api/v1/patrons.t

Signed-off-by: Bernardo Gonzalez Kriegel <bgkriegel@gmail.com>

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
2016-05-04 13:47:57 +00:00
..
Acquisition Bug 14778: Remove t/Acquisition/Invoices.t 2015-10-23 12:01:19 -03:00
Biblio Bug 5979: follow to fix spelling 2016-04-22 03:14:23 +00:00
Budgets
Circulation Bug 14632: Add Copyright for the Koha Dev Team 2016-04-29 18:06:40 +00:00
DataTables Bug 15252 - Patron search on start with does not work with several terms 2015-12-30 13:05:54 +00:00
db_dependent Bug 16408: Fix UsageStats.t 2016-05-03 15:47:02 +00:00
edi_testfiles Bug 7736: Support Ordering via Edifact EDI messages 2016-04-01 20:03:17 +00:00
External Bug 14147: Add unit tests to C4::External::OverDrive 2015-05-14 11:11:58 -03:00
Koha Bug 12748: (QA followup) make new tests pass 2016-04-26 20:20:14 +00:00
lib Bug 16155: Composite keys in TestBuilder and more 2016-05-04 13:47:57 +00:00
Members Bug 14778: Use mock_dbh where it should be used 2015-10-23 12:01:18 -03:00
Number Bug 15084: Replace C4::Budgets::GetCurrencies with Koha::Acquisition::Currencies->search 2016-03-03 20:39:01 +00:00
Search
Serials
00-checkdatabase-version.t Bug 9978: Replace license header with the correct license (GPLv3+) 2015-04-20 09:59:38 -03:00
00-deprecated.t
00-load.t Bug 7904 Change SIP modules to use standard LIB path 2015-02-05 14:44:54 -03:00
00-merge-conflict-markers.t Bug 9978: Replace license header with the correct license (GPLv3+) 2015-04-20 09:59:38 -03:00
00-testcritic.t Bug 15258: Prevent unused declared variables 2015-12-30 17:24:30 -07:00
00-valid-xml.t Bug 9978: Replace license header with the correct license (GPLv3+) 2015-04-20 09:59:38 -03:00
Auth_with_shibboleth.t Bug 15611: Fix another implimented vs implemented 2016-01-27 05:17:21 +00:00
AuthoritiesMarc_MARC21.t
AuthoritiesMarc_UNIMARC.t
AuthUtils.t
Barcodes_annual.t
Barcodes_EAN13.t
Barcodes_hbyymmincr.t
Barcodes_incremental.t
Biblio.t Bug 16169: Change prototype for C4::Biblio::TransformMarcToKoha 2016-04-07 00:04:21 +00:00
Bookseller.t
Boolean.t Bug 13814: (QA followup) test for generated warnings 2015-03-15 09:03:33 -03:00
Branch.t
Breeding.t Bug 13279: t/Breeding.t shouldn't depend on the DB 2014-11-20 09:39:53 -03:00
Budgets.t
Cache.t Bug 16229: Add the unsafe flag to set_in_cache 2016-04-20 17:17:21 +00:00
Calendar.t Bug 15150: Make t/ tests skip if Test::DBIx::Class absent 2015-11-06 12:25:27 -03:00
Charset.t Bug 14112: Silence warnings in t/Charset.t 2015-05-27 14:32:41 -03:00
Circulation_barcodedecode.t Bug 15151: Avoid DB access to load C4::Members 2015-11-08 13:10:13 -03:00
ClassSortRoutine.t
ClassSortRoutine_Dewey.t
ClassSortRoutine_Generic.t
ClassSortRoutine_LCC.t
ClassSource.t
Context.t Bug 14751: [QA Follow-up] Unit tests for interface method 2016-03-02 04:21:26 +00:00
Contract.t
Creators.t Bug 12194: add more tests for pdf creation 2015-10-22 09:42:21 -03:00
DateUtils.t Bug 15445 DateUtils.t fails on Jenkins due to server sluggishness 2016-03-08 21:55:16 +00:00
Debug.t Bug 14114: Silence warns and cleanup t/Debug.t 2015-05-22 09:33:34 -03:00
dummy.t
Edifact.t Bug 7736: Support Ordering via Edifact EDI messages 2016-04-01 20:03:17 +00:00
EdiInvoice.t Bug 7736: Support Ordering via Edifact EDI messages 2016-04-01 20:03:17 +00:00
Ediorder.t Bug 7736: Support Ordering via Edifact EDI messages 2016-04-01 20:03:17 +00:00
Ediordrsp.t Bug 7736: Support Ordering via Edifact EDI messages 2016-04-01 20:03:17 +00:00
External_Syndetics.t
Form_MessagingPreferences.t
Heading.t
Images.t Bug 15150: Make t/ tests skip if Test::DBIx::Class absent 2015-11-06 12:25:27 -03:00
ImportBatch.t Bug 13281: t/ImportBatch.t shouldn't depend on the DB 2014-11-20 09:53:36 -03:00
Installer_PerlDependencies.t
Installer_PerlModules.t
Installer_pm.t
ItemCirculationAlertPreference.t
Koha.t Bug 15800: Koha::AuthorisedValues - Remove C4::Koha::IsAuthorisedValueCategory 2016-03-02 03:54:16 +00:00
Koha_Email.t
Koha_MetadataRecord.t Bug 8064: Fix unit tests for createMergeHash 2015-11-09 15:08:57 -03:00
Koha_Template_Plugin_Cache.t
Koha_Template_Plugin_Koha.t Bug 13758: (QA followup) revert case change that broke the tests 2015-05-07 14:12:14 -03:00
Koha_Util_FrameworkPlugin.t Bug 13437: Preliminary changes for marc21 plugins field 008 2015-06-10 12:51:26 -03:00
Koha_Util_MARC.t Bug 8064: Fix unit tests for createMergeHash 2015-11-09 15:08:57 -03:00
Labels.t Bug 9978: (followup) Replace license header with the correct license (GPLv3+) 2015-04-20 09:59:43 -03:00
Labels_split_ccn.t Bug 9978: (followup) Replace license header with the correct license (GPLv3+) 2015-04-20 09:59:43 -03:00
Labels_split_ddcn.t Bug 9978: (followup) Replace license header with the correct license (GPLv3+) 2015-04-20 09:59:43 -03:00
Labels_split_lccn.t Bug 9978: (followup) Replace license header with the correct license (GPLv3+) 2015-04-20 09:59:43 -03:00
Languages.t Bug 15719: Silence warning in C4/Language.pm during web install - tests 2016-02-24 01:55:27 +00:00
Letters.t Bug 15150: Make t/ tests skip if Test::DBIx::Class absent 2015-11-06 12:25:27 -03:00
Log.t
Logger.t Bug 14167: (QA followup) use warn instead of just STDERR 2015-07-21 10:50:17 -03:00
Matcher.t Bug 15150: Make t/ tests skip if Test::DBIx::Class absent 2015-11-06 12:25:27 -03:00
Members_Attributes.t Bug 12267: Remove borrower_attributes.password 2016-04-22 23:08:32 +00:00
Members_AttributeTypes.t Bug 12267: Remove borrower_attributes.password 2016-04-22 23:08:32 +00:00
Members_Messaging.t
Message.t Bug 13282: t/Message.t shouldn't depend on the DB 2014-11-20 09:38:02 -03:00
NorwegianPatronDB.t Bug 11401: (followup) make tests run on absent deps 2014-11-14 15:32:25 -03:00
OpenLibrarySearch.t Bug 6624: Add test for OpenLibrary 2016-02-23 22:04:15 +00:00
Output.t Bug 11944: use CGI( -utf8 ) everywhere 2015-01-13 13:07:21 -03:00
Output_JSONStream.t
Overdues.t Bug 13283: t/Overdues.t shouldn't depend on the DB 2014-11-20 09:37:39 -03:00
Patron.t Bug 15548: Move new patron related code to Patron* 2016-03-03 14:38:26 -07:00
Patroncards.t
Patroncards_Batch.t
Patroncards_Layout.t
Patroncards_Lib.t
Patroncards_Patroncard.t
Patroncards_Profile.t
Patroncards_Template.t
perlcriticrc Bug 15258: Prevent unused declared variables 2015-12-30 17:24:30 -07:00
Prices.t Bug 15323: Use fixtures for the active currency 2016-03-31 18:17:30 +00:00
Print.t
QueryParser.t
RecordProcessor.t Bug 15871: Improve PerlCritic level for t/RecordProcessor.t 2016-03-03 22:02:50 +00:00
Review.t
Ris.t Bug 16199: Remove C4::Ris::charconv 2016-04-06 23:59:45 +00:00
RotatingCollections.t Bug 13284: t/RotatingCollections.t shouldn't depend on the DB 2014-11-20 09:37:20 -03:00
Scheduler.t
Scrubber.t Bug 14116: Silence noisy output for t/Scrubber. 2015-06-01 14:10:56 -03:00
Search.t Bug 13278: (QA followup) use t::lib::Mocks 2014-11-19 18:11:58 -03:00
Search_PazPar2.t Bug 14117: Silence warnings t/SearchPazPar2.t 2015-06-01 14:10:14 -03:00
SimpleMARC.t Bug 14098: Implement the copy_and_replace action for MTT 2015-09-07 11:17:13 -03:00
SIP_Sip.t Bug 7904 Change SIP modules to use standard LIB path 2015-02-05 14:44:54 -03:00
smolder_smoke_signal
SMS.t
SocialData.t Bug 15150: Make t/ tests skip if Test::DBIx::Class absent 2015-11-06 12:25:27 -03:00
Stats.t
SuggestionEngine.t
SuggestionEngine_AuthorityFile.t Bug 13277: (QA followup) use t::lib::Mocks 2014-11-19 18:12:03 -03:00
TmplToken.t
XSLT.t Bug 13276: use t::lib::Mocks::mock_dbh 2014-11-19 11:30:45 -03:00