@@ -, +, @@ easy Test object creation/deletion from HASHes. -letters -overuderules -circulationrules -borrowers -biblios -items -issues (checkouts) {firstname => 'Olli-Antti', surname => 'Kivi', cardnumber => '1A01', branchcode => 'CPL', flags => '1', #superlibrarian, not exactly a very good way of doing permission testing? userid => 'mini_admin', password => $password, }, ], undef, $testContext); ... #Run your tests here warn $@; tearDown(); exit 1; t::db_dependent::TestObjects::ObjectFactory->tearDownTestContext($testContext); --- t/lib/TestObjects/BiblioFactory.pm | 115 ++++++++++++ t/lib/TestObjects/BorrowerFactory.pm | 182 ++++++++++++++++++ t/lib/TestObjects/CheckoutFactory.pm | 182 ++++++++++++++++++ t/lib/TestObjects/ItemFactory.pm | 115 ++++++++++++ t/lib/TestObjects/LetterTemplateFactory.pm | 103 +++++++++++ t/lib/TestObjects/ObjectFactory.pm | 186 +++++++++++++++++++ t/lib/TestObjects/objectFactories.t | 284 +++++++++++++++++++++++++++++ 7 files changed, 1167 insertions(+) create mode 100644 t/lib/TestObjects/BiblioFactory.pm create mode 100644 t/lib/TestObjects/BorrowerFactory.pm create mode 100644 t/lib/TestObjects/CheckoutFactory.pm create mode 100644 t/lib/TestObjects/ItemFactory.pm create mode 100644 t/lib/TestObjects/LetterTemplateFactory.pm create mode 100644 t/lib/TestObjects/ObjectFactory.pm create mode 100644 t/lib/TestObjects/objectFactories.t --- a/t/lib/TestObjects/BiblioFactory.pm +++ a/t/lib/TestObjects/BiblioFactory.pm @@ -0,0 +1,115 @@ +package t::lib::TestObjects::BiblioFactory; + +# Copyright Vaara-kirjastot 2015 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +use Modern::Perl; +use Carp; + +use C4::Biblio; + +use base qw(t::lib::TestObjects::ObjectFactory); + +sub new { + my ($class) = @_; + + my $self = {}; + bless($self, $class); + return $self; +} + +=head t::lib::TestObjects::createTestGroup + + my $biblioFactory = t::lib::TestObjects::BiblioFactory->new(); + my $records = $biblioFactory->createTestGroup([ + {'biblio.title' => 'I wish I met your mother', + 'biblio.author' => 'Pertti Kurikka', + 'biblio.copyrightdate' => '1960', + 'biblioitems.isbn' => '9519671580', + 'biblioitems.itemtype' => 'BK', + }, + ], undef, $testContext1, $testContext2, $testContext3); + +Calls C4::Biblio::TransformKohaToMarc() to make a MARC::Record and add it to +the DB. Returns a HASH of MARC::Records. +The HASH is keyed with the biblionumber, or the given $hashKey. Using for example +'biblioitems.isbn' is very much recommended to make linking objects more easy. +The biblionumber is injected to the MARC::Record-object to be easily accessable, +so we can get it like this: + $records->{$key}->{biblionumber}; + +See C4::Biblio::TransformKohaToMarc() for how the biblio- or biblioitem-tables' +columns need to be given. + +See t::lib::TestObjects::ObjectFactory for more documentation +=cut + +sub createTestGroup { + my ($self, $biblios, $hashKey, $featureStash, $scenarioStash, $stepStash) = @_; + $self->_validateStashes($featureStash, $scenarioStash, $stepStash); + + my %records; + foreach my $biblio (@$biblios) { + my $record = C4::Biblio::TransformKohaToMarc($biblio); + my ($biblionumber, $biblioitemnumber) = C4::Biblio::AddBiblio($record,''); + $record->{biblionumber} = $biblionumber; + + my $key = $self->getHashKey($biblio, $biblionumber, $hashKey); + + $records{$key} = $record; + } + + $self->_persistToStashes(\%records, 'biblios', $featureStash, $scenarioStash, $stepStash); + + return \%records; +} + +=head + + my $records = createTestGroup(); + ##Do funky stuff + deleteTestGroup($records); + +Removes the given test group from the DB. + +=cut + +sub deleteTestGroup { + my ($self, $records) = @_; + + my ( $biblionumberFieldCode, $biblionumberSubfieldCode ) = + C4::Biblio::GetMarcFromKohaField( "biblio.biblionumber", '' ); + + my $schema = Koha::Database->new_schema(); + while( my ($key, $record) = each %$records) { + my $biblionumber = $record->subfield($biblionumberFieldCode, $biblionumberSubfieldCode); + $schema->resultset('Biblio')->search($biblionumber)->delete_all(); + $schema->resultset('Biblioitem')->search($biblionumber)->delete_all(); + } +} +sub _deleteTestGroupFromIdentifiers { + my ($self, $testGroupIdentifiers) = @_; + + my $schema = Koha::Database->new_schema(); + foreach my $isbn (@$testGroupIdentifiers) { + $schema->resultset('Biblio')->search({"biblioitems.isbn" => $isbn},{join => 'biblioitems'})->delete(); + $schema->resultset('Biblioitem')->search({isbn => $isbn})->delete(); + } +} + +1; --- a/t/lib/TestObjects/BorrowerFactory.pm +++ a/t/lib/TestObjects/BorrowerFactory.pm @@ -0,0 +1,182 @@ +package t::lib::TestObjects::BorrowerFactory; + +# Copyright Vaara-kirjastot 2015 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +use Modern::Perl; +use Carp; +use Scalar::Util qw(blessed); + +use C4::Members; +use Koha::Borrowers; + +use base qw(t::lib::TestObjects::ObjectFactory); + +sub new { + my ($class) = @_; + + my $self = {}; + bless($self, $class); + return $self; +} + +=head createTestGroup( $data [, $hashKey, $testContexts...] ) +@OVERLOADED + + my $borrowerFactory = t::lib::TestObjects::BorrowerFactory->new(); + my $borrowers = $borrowerFactory->createTestGroup([ + {firstname => 'Olli-Antti', + surname => 'Kivi', + cardnumber => '11A001', + branchcode => 'CPL', + }, + {firstname => 'Olli-Antti2', + surname => 'Kivi2', + cardnumber => '11A002', + branchcode => 'FPL', + }, + ], undef, $testContext1, $testContext2, $testContext3); + + #Do test stuff... + + t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext1); + t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext2); + t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext3); + +The HASH is keyed with the given $hashKey or 'koha.borrowers.cardnumber' +See C4::Members::AddMember() for how the table columns need to be given. + +@PARAM1 ARRAYRef of HASHRefs of C4::Members::AddMember()-parameters. +@PARAM2 koha.borrower-column which is used as the test context borrowers HASH key, + defaults to the most best option cardnumber. +@PARAM3-5 HASHRef of test contexts. You can save the given borrowers to multiple + test contexts. Usually one is enough. These test contexts are + used to help tear down DB changes. +@RETURNS HASHRef of $hashKey => $borrower-objects: + +See t::lib::TestObjects::ObjectFactory for more documentation +=cut + +sub createTestGroup { + my ($self, $objects, $hashKey, $featureStash, $scenarioStash, $stepStash) = @_; + $self->_validateStashes($featureStash, $scenarioStash, $stepStash); + $hashKey = 'cardnumber' unless $hashKey; + + my %objects; + foreach my $object (@$objects) { + + $self->validateAndPopulateDefaultValues($object, $hashKey); + + #Try to add the Borrower, but it might fail because of the barcode or other UNIQUE constraint. + #Catch the error and try looking for the Borrower if we suspect it is present in the DB. + my $borrowernumber; + eval { + $borrowernumber = C4::Members::AddMember(%$object); + }; + if ($@) { + if (blessed($@) && $@->isa('DBIx::Class::Exception') && + $@->{msg} =~ /Duplicate entry '.+?' for key 'cardnumber'/) { #DBIx should throw other types of exceptions instead of this general type :( + #This exception type is OK, we ignore this and try fetching the existing Object next. + warn "Recovering from duplicate exception.\n"; + } + else { + die $@; + } + } + + #If adding failed, we still get some strange borrowernumber result. + #Check for sure by finding the real borrower. + my $borrower = Koha::Borrowers->cast( $borrowernumber || $object ); + unless ($borrower) { + carp "BorrowerFactory:> No borrower for cardnumber '".$object->{cardnumber}."'"; + next(); + } + + my $key = $self->getHashKey($borrower, $borrowernumber, $hashKey); + + $objects{$key} = $borrower; + } + + $self->_persistToStashes(\%objects, 'borrowers', $featureStash, $scenarioStash, $stepStash); + + return \%objects; +} + +=head validateAndPopulateDefaultValues +@OVERLOAD + +Validates given Object parameters and makes sure that critical fields are given +and populates defaults for missing values. +=cut + +sub validateAndPopulateDefaultValues { + my ($self, $borrower, $hashKey) = @_; + $self->SUPER::validateAndPopulateDefaultValues($borrower, $hashKey); + + $borrower->{categorycode} = 'PT' unless $borrower->{categorycode}; + $borrower->{branchcode} = 'CPL' unless $borrower->{branchcode}; + $borrower->{dateofbirth} = '1985-10-12' unless $borrower->{dateofbirth}; +} + +=head deleteTestGroup +@OVERLOADED + + my $records = createTestGroup(); + ##Do funky stuff + deleteTestGroup($records); + +Removes the given test group from the DB. + +=cut + +sub deleteTestGroup { + my ($self, $objects) = @_; + + my $schema = Koha::Database->new_schema(); + while( my ($key, $object) = each %$objects) { + my $borrower = Koha::Borrowers->cast($object); + eval { + $borrower->delete(); + }; + if ($@) { + if (blessed($@) && $@->isa('DBIx::Class::Exception') && + #Trying to recover. Delete all Checkouts for the Borrower to be able to delete. + $@->{msg} =~ /a foreign key constraint fails.+?issues_ibfk_1/) { #DBIx should throw other types of exceptions instead of this general type :( + + my @checkouts = Koha::Checkouts->search({borrowernumber => $borrower->borrowernumber}); + foreach my $c (@checkouts) { $c->delete(); } + $borrower->delete(); + warn "Recovering from foreign key exception.\n"; + } + else { + die $@; + } + } + + } +} +sub _deleteTestGroupFromIdentifiers { + my ($self, $testGroupIdentifiers) = @_; + + my $schema = Koha::Database->new_schema(); + foreach my $key (@$testGroupIdentifiers) { + $schema->resultset('Borrower')->find({"cardnumber" => $key})->delete(); + } +} + +1; --- a/t/lib/TestObjects/CheckoutFactory.pm +++ a/t/lib/TestObjects/CheckoutFactory.pm @@ -0,0 +1,182 @@ +package t::lib::TestObjects::CheckoutFactory; + +# Copyright Vaara-kirjastot 2015 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +use Modern::Perl; +use Carp; +use DateTime; + +use C4::Circulation; +use C4::Members; +use C4::Items; +use Koha::Borrowers; +use Koha::Items; + +use base qw(t::lib::TestObjects::ObjectFactory); + +sub new { + my ($class) = @_; + + my $self = {}; + bless($self, $class); + return $self; +} + +=head t::lib::TestObjects::CheckoutFactory::createTestGroup( $data [, $hashKey, $checkoutBranchRule] ) + + my $checkoutFactory = t::lib::TestObjects::CheckoutFactory->new(); + my $checkouts = $checkoutFactory->createTestGroup([ + {#Checkout params + }, + {#More checkout params + }, + ], undef, $testContext1, $testContext2, $testContext3); + + t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext1); + +@PARAM1, ARRAY of HASHes. + [ { + cardnumber => '167Azava0001', + barcode => '167Nfafa0010', + daysOverdue => 7, #This Checkout's duedate was 7 days ago. If undef, then uses today as the checkout day. + daysAgoCheckedout => 28, #This Checkout hapened 28 days ago. If undef, then uses today. + }, + { + ... + } + ] +@PARAM2, String, the HASH-element to use as the returning HASHes key. +@PARAM3, String, the rule on where to check these Issues out: + 'homebranch', uses the Item's homebranch as the checkout branch + 'holdingbranch', uses the Item's holdingbranch as the checkout branch + undef, uses the current Environment branch + '', checks out all Issues from the given branchCode +@PARAM4-6 HASHRef of test contexts. You can save the given objects to multiple + test contexts. Usually one is enough. These test contexts are + used to help tear down DB changes. +@RETURNS HASHRef of $hashKey => $checkout-objects. + The HASH is keyed with -, or the given $hashKey. + Example: { + '11A001-167N0212' => { + cardnumber => , + barcode => , + ...other Checkout-object columns... + }, + ... +} +=cut + +sub createTestGroup { + my ($self, $objects, $hashKey, $checkoutBranchRule, $featureStash, $scenarioStash, $stepStash) = @_; + $self->_validateStashes($featureStash, $scenarioStash, $stepStash); + + #If running this test factory from unit tests or bare script, the context might not have been initialized. + unless (C4::Context->userenv()) { + C4::Context->_new_userenv('testGroupsTest'); + C4::Context->set_userenv(undef, undef, undef, + undef, undef, + 'CPL', undef, undef, + undef, undef, undef); + } + my $oldContextBranch = C4::Context->userenv()->{branch}; + + my %objects; + foreach my $checkoutParams (@$objects) { + my $borrower = C4::Members::GetMember(cardnumber => $checkoutParams->{cardnumber}); + my $item = Koha::Items->cast($checkoutParams->{barcode}); + + my $duedate = DateTime->now(time_zone => C4::Context->tz()); + if ($checkoutParams->{daysOverdue}) { + $duedate->subtract(days => $checkoutParams->{daysOverdue} ); + } + + my $checkoutdate = DateTime->now(time_zone => C4::Context->tz()); + if ($checkoutParams->{daysAgoCheckedout}) { + $checkoutdate->subtract(days => $checkoutParams->{daysAgoCheckedout} ); + } + + #Set the checkout branch + my $checkoutBranch; + if (not($checkoutBranchRule)) { + #Use the existing userenv()->{branch} + } + elsif ($checkoutBranchRule eq 'homebranch') { + $checkoutBranch = $item->homebranch; + } + elsif ($checkoutBranchRule eq 'holdingbranch') { + $checkoutBranch = $item->holdingbranch; + } + elsif ($checkoutBranchRule) { + $checkoutBranch = $checkoutBranchRule; + } + C4::Context->userenv()->{branch} = $checkoutBranch if $checkoutBranch; + + my $datedue = C4::Circulation::AddIssue( $borrower, $checkoutParams->{barcode}, $duedate, undef, $checkoutdate ); + #We want the issue_id as well. + my $checkout = Koha::Checkouts->find({ borrowernumber => $borrower->{borrowernumber}, itemnumber => $item->itemnumber }); + unless ($checkout) { + carp "CheckoutFactory:> No checkout for cardnumber '".$checkoutParams->{cardnumber}."' and barcode '".$checkoutParams->{barcode}."'"; + next(); + } + + my $key; + if ($hashKey) { + $key = $self->getHashKey($checkout, $checkout->issue_id, $hashKey); + } + else { + $key = $checkoutParams->{cardnumber}.'-'.$checkoutParams->{barcode}; + } + + $objects{$key} = $checkout; + } + + $self->_persistToStashes(\%objects, 'checkouts', $featureStash, $scenarioStash, $stepStash); + + C4::Context->userenv()->{branch} = $oldContextBranch; + return \%objects; +} + +=head + + my $objects = createTestGroup(); + ##Do funky stuff + deleteTestGroup($records); + +Removes the given test group from the DB. + +=cut + +sub deleteTestGroup { + my ($self, $objects) = @_; + + while( my ($key, $object) = each %$objects) { + my $checkout = Koha::Checkouts->cast($object); + $checkout->delete(); + } +} +sub _deleteTestGroupFromIdentifiers { + my ($self, $testGroupIdentifiers) = @_; + + my $schema = Koha::Database->new_schema(); + foreach my $key (@$testGroupIdentifiers) { + $schema->resultset('Issue')->find({"issue_id" => $key})->delete(); + } +} + +1; --- a/t/lib/TestObjects/ItemFactory.pm +++ a/t/lib/TestObjects/ItemFactory.pm @@ -0,0 +1,115 @@ +package t::lib::TestObjects::ItemFactory; + +# Copyright Vaara-kirjastot 2015 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +use Modern::Perl; +use Carp; + +use C4::Items; +use Koha::Items; + +use base qw(t::lib::TestObjects::ObjectFactory); + +sub new { + my ($class) = @_; + + my $self = {}; + bless($self, $class); + return $self; +} + +=head t::lib::TestObjects::ItemFactory::createTestGroup( $data [, $hashKey] ) +@OVERLOADED + +Returns a HASH of objects. +Each Item is expected to contain the biblionumber of the Biblio they are added into. + eg. $item->{biblionumber} = 550242; + +The HASH is keyed with the PRIMARY KEY, or the given $hashKey. + +See C4::Items::AddItem() for how the table columns need to be given. + +See t::lib::TestObjects::ObjectFactory for more documentation +=cut + +sub createTestGroup { + my ($self, $objects, $hashKey, $featureStash, $scenarioStash, $stepStash) = @_; + $self->_validateStashes($featureStash, $scenarioStash, $stepStash); + + my %objects; + foreach my $object (@$objects) { + my ($biblionumber, $biblioitemnumber, $itemnumber); + eval { + ($biblionumber, $biblioitemnumber, $itemnumber) = C4::Items::AddItem($object, $object->{biblionumber}); + }; + if ($@) { + if (blessed($@) && $@->isa('DBIx::Class::Exception') && + $@->{msg} =~ /Duplicate entry '.+?' for key 'itembarcodeidx'/) { #DBIx should throw other types of exceptions instead of this general type :( + #This exception type is OK, we ignore this and try fetching the existing Object next. + warn "Recovering from duplicate exception.\n"; + } + else { + die $@; + } + } + my $item = Koha::Items->cast($itemnumber || $object); + unless ($item) { + carp "ItemFactory:> No item for barcode '".$object->{barcode}."'"; + next(); + } + + my $key = $self->getHashKey($item, $itemnumber, $hashKey); + + $objects{$key} = $item; + } + + $self->_persistToStashes(\%objects, 'items', $featureStash, $scenarioStash, $stepStash); + + return \%objects; +} + +=head +@OVERLOADED + + my $objects = createTestGroup(); + ##Do funky stuff + deleteTestGroup($records); + +Removes the given test group from the DB. + +=cut + +sub deleteTestGroup { + my ($self, $objects) = @_; + + while( my ($key, $object) = each %$objects) { + my $item = Koha::Items->cast($object); + $item->delete(); + } +} +sub _deleteTestGroupFromIdentifiers { + my ($self, $testGroupIdentifiers) = @_; + + foreach my $key (@$testGroupIdentifiers) { + my $item = Koha::Items->cast($key); + $item->delete(); + } +} + +1; --- a/t/lib/TestObjects/LetterTemplateFactory.pm +++ a/t/lib/TestObjects/LetterTemplateFactory.pm @@ -0,0 +1,103 @@ +package t::lib::TestObjects::LetterTemplateFactory; + +# Copyright Vaara-kirjastot 2015 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +use Modern::Perl; +use Carp; + +use C4::Letters; +use Koha::LetterTemplates; + +use base qw(t::lib::TestObjects::ObjectFactory); + +sub new { + my ($class) = @_; + + my $self = {}; + bless($self, $class); + return $self; +} + +=head t::lib::TestObjects::LetterTemplateFactory->createTestGroup +Returns a HASH of Koha::LetterTemplate-objects +The HASH is keyed with the PRIMARY KEYS eg. 'circulation-ODUE2-CPL-print', or the given $hashKey. +=cut + +#Incredibly the Letters-module has absolutely no Create or Update-component to operate on Letter templates? +#Tests like these are brittttle. :( +sub createTestGroup { + my ($self, $objects, $hashKey, $featureStash, $scenarioStash, $stepStash) = @_; + $self->_validateStashes($featureStash, $scenarioStash, $stepStash); + + my %objects; + my $schema = Koha::Database->new()->schema(); + foreach my $object (@$objects) { + my $rs = $schema->resultset('Letter'); + my $result = $rs->update_or_create({ + module => $object->{module}, + code => $object->{code}, + branchcode => ($object->{branchcode}) ? $object->{branchcode} : '', + name => $object->{name}, + is_html => $object->{is_html}, + title => $object->{title}, + message_transport_type => $object->{message_transport_type}, + content => $object->{content}, + }); + + my @pks = $result->id(); + my $key = $self->getHashKey($object, join('-',@pks), $hashKey); + + $objects{$key} = Koha::LetterTemplates->cast($result); + } + + $self->_persistToStashes(\%objects, 'letterTemplates', $featureStash, $scenarioStash, $stepStash); + + return \%objects; +} + +=head + +Removes the given test group from the DB. + +=cut + +sub deleteTestGroup { + my ($self, $letterTemplates) = @_; + + my $schema = Koha::Database->new_schema(); + while( my ($key, $letterTemplate) = each %$letterTemplates ) { + $letterTemplate->delete(); + } +} + +sub _deleteTestGroupFromIdentifiers { + my $testGroupIdentifiers = shift; + + my $schema = Koha::Database->new_schema(); + foreach my $key (@$testGroupIdentifiers) { + my ($module, $code, $branchcode, $mtt) = split('-',$key); + $schema->resultset('Letter')->find({module => $module, + code => $code, + branchcode => $branchcode, + message_transport_type => $mtt, + })->delete(); + } +} + +1; --- a/t/lib/TestObjects/ObjectFactory.pm +++ a/t/lib/TestObjects/ObjectFactory.pm @@ -0,0 +1,186 @@ +package t::lib::TestObjects::ObjectFactory; + +# Copyright Vaara-kirjastot 2015 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +use Modern::Perl; +use Carp; + +use Koha::Exception::BadParameter; + +=head createTestGroup( $data [, $hashKey, $testContexts...] ) +@ABSTRACT, OVERLOAD THIS FROM SUBCLASS + + my $factory = t::lib::TestObjects::ObjectFactory->new(); + my $objects = $factory->createTestGroup([ + #Imagine if using the BorrowerFactory + {firstname => 'Olli-Antti', + surname => 'Kivi', + cardnumber => '11A001', + branchcode => 'CPL', + ... + }, + #Or if using the ItemFactory + {biblionumber => 123413, + barcode => '11N002', + homebranch => 'FPL', + ... + }, + ], $hashKey, $testContext1, $testContext2, $testContext3); + + #Do test stuff... + + t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext1); + t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext2); + t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext3); + +The HASH is keyed with the given $hashKey or 'koha..cardnumber' +See the object constructor defined in the implementing Factory-class for how +the table columns need to be given. + +@PARAM1 ARRAYRef of HASHRefs of desired Object constructor parameters +@PARAM2 koha.-column which is used as the test context HASH key to find individual Objects, + defaults to to one of the UNIQUE database keys. +@PARAM3-5 HASHRef of test contexts. You can save the given Objects to multiple + test contexts. Usually one is enough. These test contexts are + used to help tear down DB changes. +@RETURNS HASHRef of $hashKey => Objects, eg. + { + borrowers => { $hashKey => {#borrower1 HASH}, + $hashKey => {#borrower2 HASH}, + } + } +=cut + +sub createTestGroup {} #OVERLOAD THIS FROM SUBCLASS +sub deleteTestGroup {} #OVERLOAD THIS FROM SUBCLASS + +=head tearDownTestContext + +Given a testContext stash populated using one of the TestObjectFactory implementations createTestGroup()-subroutines, +Removes all the persisted objects in the stash. + +TestObjectFactories must be lazy loaded here to make it possible for them to subclass this. +=cut + +sub tearDownTestContext { + my ($self, $stash) = @_; + + ##You should introduce tearDowns in such an order that to not provoke FOREIGN KEY issues. + if ($stash->{checkouts}) { + require t::lib::TestObjects::CheckoutFactory; + t::lib::TestObjects::CheckoutFactory->deleteTestGroup($stash->{checkouts}); + delete $stash->{checkouts}; + } + if ($stash->{items}) { + require t::lib::TestObjects::ItemFactory; + t::lib::TestObjects::ItemFactory->deleteTestGroup($stash->{items}); + delete $stash->{items}; + } + if ($stash->{biblios}) { + require t::lib::TestObjects::BiblioFactory; + t::lib::TestObjects::BiblioFactory->deleteTestGroup($stash->{biblios}); + delete $stash->{biblios}; + } + if ($stash->{borrowers}) { + require t::lib::TestObjects::BorrowerFactory; + t::lib::TestObjects::BorrowerFactory->deleteTestGroup($stash->{borrowers}); + delete $stash->{borrowers}; + } + if ($stash->{letterTemplates}) { + require t::lib::TestObjects::LetterTemplateFactory; + t::lib::TestObjects::LetterTemplateFactory->deleteTestGroup($stash->{letterTemplates}); + delete $stash->{letterTemplates}; + } +} + +sub getHashKey { + my ($self, $object, $primaryKey, $hashKey) = @_; + + if (ref($object) eq 'HASH') { + if ($hashKey && not($object->{$hashKey})) { + carp ref($self)."->getHashKey($object, $primaryKey, $hashKey):> Given ".ref($object)." has no \$hashKey '$hashKey'."; + } + return ($hashKey) ? $object->{$hashKey} : $primaryKey; + } + else { + if ($hashKey && not($object->$hashKey())) { + carp ref($self)."->getHashKey($object, $primaryKey, $hashKey):> Given ".ref($object)." has no \$hashKey '$hashKey'."; + } + return ($hashKey) ? $object->$hashKey() : $primaryKey; + } +} + +=head validateAndPopulateDefaultValues +@INTERFACE + +Validates given Object parameters and makes sure that critical fields are given +and populates defaults for missing values. +You must overload this in the subclassing factory if you want to validate and check the given parameters +=cut + +sub validateAndPopulateDefaultValues { + my ($self, $object, $hashKey) = @_; + + unless ($object->{$hashKey}) { + Koha::Exception::BadParameter->throw(error => ref($self)."():> You want to access test Objects using hashKey '$hashKey', but you haven't supplied it as a Object parameter. ObjectFactories need a unique identifier to function properly."); + } +} + +=head _validateStashes + + _validateStashes($featureStash, $scenarioStash, $stepStash); + +Validates that the given stahses are what they are supposed to be... , HASHrefs. +@THROWS Koha::Exception::BadParameter, if validation failed. +=cut + +sub _validateStashes { + my ($self, $featureStash, $scenarioStash, $stepStash) = @_; + + if ($featureStash && not(ref($featureStash) eq 'HASH')) { + Koha::Exception::BadParameter->throw(error => __PACKAGE__."->_validateStashes():> Stash '\$featureStash' is not a HASHRef! Leave it 'undef' if you don't want to use it."); + } + if ($scenarioStash && not(ref($scenarioStash) eq 'HASH')) { + Koha::Exception::BadParameter->throw(error => __PACKAGE__."->_validateStashes():> Stash '\$scenarioStash' is not a HASHRef! Leave it 'undef' if you don't want to use it."); + } + if ($stepStash && not(ref($stepStash) eq 'HASH')) { + Koha::Exception::BadParameter->throw(error => __PACKAGE__."->_validateStashes():> Stash '\$stepStash' is not a HASHRef! Leave it 'undef' if you don't want to use it."); + } +} + +=head _persistToStashes + + _persistToStashes($objects, $stashKey, $featureStash, $scenarioStash, $stepStash); + +Saves the given HASH to the given stashes using the given stash key. +=cut + +sub _persistToStashes { + my ($self, $objects, $stashKey, $featureStash, $scenarioStash, $stepStash) = @_; + + if ($featureStash || $scenarioStash || $stepStash) { + while( my ($key, $borrower) = each %$objects) { + $featureStash->{$stashKey}->{ $key } = $borrower if $featureStash; + $scenarioStash->{$stashKey}->{ $key } = $borrower if $scenarioStash; + $stepStash->{$stashKey}->{ $key } = $borrower if $stepStash; + } + } +} + +1; --- a/t/lib/TestObjects/objectFactories.t +++ a/t/lib/TestObjects/objectFactories.t @@ -0,0 +1,284 @@ +#!/usr/bin/perl + +# Copyright Vaara-kirjastot 2015 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +use Modern::Perl; + +use Test::More; +use DateTime; + +use Koha::DateUtils; + +use t::lib::TestObjects::ObjectFactory; +use t::lib::TestObjects::BorrowerFactory; +use Koha::Borrowers; +use t::lib::TestObjects::ItemFactory; +use Koha::Items; +use t::lib::TestObjects::BiblioFactory; +use Koha::Biblios; +use t::lib::TestObjects::CheckoutFactory; +use Koha::Checkouts; +use t::lib::TestObjects::LetterTemplateFactory; +use Koha::LetterTemplates; + + +my $testContext = {}; #Gather all created Objects here so we can finally remove them all. + + + +########## BorrowerFactory subtests ########## +subtest 't::lib::TestObjects::BorrowerFactory' => sub { + my $subtestContext = {}; + ##Create and Delete. Add one + my $f = t::lib::TestObjects::BorrowerFactory->new(); + my $objects = $f->createTestGroup([ + {firstname => 'Olli-Antti', + surname => 'Kivi', + cardnumber => '11A001', + branchcode => 'CPL', + }, + ], undef, $subtestContext, undef, $testContext); + is($objects->{'11A001'}->cardnumber, '11A001', "Borrower '11A001'."); + ##Add one more to test incrementing the subtestContext. + $objects = $f->createTestGroup([ + {firstname => 'Olli-Antti2', + surname => 'Kivi2', + cardnumber => '11A002', + branchcode => 'FFL', + }, + ], undef, $subtestContext, undef, $testContext); + is($subtestContext->{borrowers}->{'11A001'}->cardnumber, '11A001', "Borrower '11A001' from \$subtestContext."); #From subtestContext + is($objects->{'11A002'}->branchcode, 'FFL', "Borrower '11A002'."); #from just created hash. + + ##Delete objects + t::lib::TestObjects::ObjectFactory->tearDownTestContext($subtestContext); + my $object11A001 = Koha::Borrowers->find({cardnumber => '11A001'}); + ok (not($object11A001), "Borrower '11A001' deleted"); + my $object11A002 = Koha::Borrowers->find({cardnumber => '11A002'}); + ok (not($object11A002), "Borrower '11A002' deleted"); + + #Prepare for autoremoval. + $objects = $f->createTestGroup([ + {firstname => 'Olli-Antti', + surname => 'Kivi', + cardnumber => '11A001', + branchcode => 'CPL', + }, + {firstname => 'Olli-Antti2', + surname => 'Kivi2', + cardnumber => '11A002', + branchcode => 'FFL', + }, + ], undef, undef, undef, $testContext); +}; + + + +########## BiblioFactory and ItemFactory subtests ########## +subtest 't::lib::TestObjects::BiblioFactory and ::ItemFactory' => sub { + my $subtestContext = {}; + ##Create and Delete. Add one + my $fb = t::lib::TestObjects::BiblioFactory->new(); + my $biblios = $fb->createTestGroup([ + {'biblio.title' => 'I wish I met your mother', + 'biblio.author' => 'Pertti Kurikka', + 'biblio.copyrightdate' => '1960', + 'biblioitems.isbn' => '9519671580', + 'biblioitems.itemtype' => 'BK', + }, + ], 'biblioitems.isbn', $subtestContext, undef, $testContext); + my $f = t::lib::TestObjects::ItemFactory->new(); + my $objects = $f->createTestGroup([ + {biblionumber => $biblios->{9519671580}->{biblionumber}, + barcode => '167Nabe0001', + homebranch => 'CPL', + holdingbranch => 'CPL', + price => '0.50', + replacementprice => '0.50', + itype => 'BK', + biblioisbn => '9519671580', + itemcallnumber => 'PK 84.2', + }, + ], 'barcode', $subtestContext, undef, $testContext); + + is($objects->{'167Nabe0001'}->barcode, '167Nabe0001', "Item '167Nabe0001'."); + ##Add one more to test incrementing the subtestContext. + $objects = $f->createTestGroup([ + {biblionumber => $biblios->{9519671580}->{biblionumber}, + barcode => '167Nabe0002', + homebranch => 'CPL', + holdingbranch => 'FFL', + price => '3.50', + replacementprice => '3.50', + itype => 'BK', + biblioisbn => '9519671580', + itemcallnumber => 'JK 84.2', + }, + ], 'barcode', $subtestContext, undef, $testContext); + + is($subtestContext->{items}->{'167Nabe0001'}->barcode, '167Nabe0001', "Item '167Nabe0001' from \$subtestContext."); + is($objects->{'167Nabe0002'}->holdingbranch, 'FFL', "Item '167Nabe0002'."); + is(ref($biblios->{9519671580}), 'MARC::Record', "Biblio 'I wish I met your mother'."); + + ##Delete objects + t::lib::TestObjects::ObjectFactory->tearDownTestContext($subtestContext); + my $object1 = Koha::Items->find({barcode => '167Nabe0001'}); + ok (not($object1), "Item '167Nabe0001' deleted"); + my $object2 = Koha::Items->find({barcode => '167Nabe0002'}); + ok (not($object2), "Item '167Nabe0002' deleted"); + my $object3 = Koha::Biblios->find({title => 'I wish I met your mother', author => "Pertti Kurikka"}); + ok (not($object2), "Biblio 'I wish I met your mother' deleted"); + + #Prepare for autoremoval. + $biblios = $fb->createTestGroup([ + {'biblio.title' => 'I wish I met your mother', + 'biblio.author' => 'Pertti Kurikka', + 'biblio.copyrightdate' => '1960', + 'biblioitems.isbn' => '9519671580', + 'biblioitems.itemtype' => 'BK', + }, + ], 'biblioitems.isbn', undef, undef, $testContext); + $objects = $f->createTestGroup([ + {biblionumber => $biblios->{9519671580}->{biblionumber}, + barcode => '167Nabe0001', + homebranch => 'CPL', + holdingbranch => 'CPL', + price => '0.50', + replacementprice => '0.50', + itype => 'BK', + biblioisbn => '9519671580', + itemcallnumber => 'PK 84.2', + }, + {biblionumber => $biblios->{9519671580}->{biblionumber}, + barcode => '167Nabe0002', + homebranch => 'CPL', + holdingbranch => 'FFL', + price => '3.50', + replacementprice => '3.50', + itype => 'BK', + biblioisbn => '9519671580', + itemcallnumber => 'JK 84.2', + }, + ], 'barcode', undef, undef, $testContext); +}; + + + +########## CheckoutFactory subtests ########## +subtest 't::lib::TestObjects::CheckoutFactory' => sub { + my $subtestContext = {}; + ##Create and Delete using dependencies in the $testContext instantiated in previous subtests. + my $f = t::lib::TestObjects::CheckoutFactory->new(); + my $objects = $f->createTestGroup([ + { + cardnumber => '11A001', + barcode => '167Nabe0001', + daysOverdue => 7, + daysAgoCheckedout => 28, + }, + { + cardnumber => '11A002', + barcode => '167Nabe0002', + daysOverdue => -7, + daysAgoCheckedout => 14, + }, + ], undef, undef, undef, undef); + + is(Koha::DateUtils::dt_from_string($objects->{'11A001-167Nabe0001'}->issuedate)->day(), + DateTime->now(time_zone => C4::Context->tz())->subtract(days => '28')->day() + , "Checkout '11A001-167Nabe0001', adjusted issuedates match."); + is(Koha::DateUtils::dt_from_string($objects->{'11A002-167Nabe0002'}->date_due)->day(), + DateTime->now(time_zone => C4::Context->tz())->subtract(days => '-7')->day() + , "Checkout '11A002-167Nabe0002', adjusted date_dues match."); + + $f->deleteTestGroup($objects); + my $object1 = Koha::Checkouts->find({borrowernumber => $objects->{'11A001-167Nabe0001'}->borrowernumber, + itemnumber => $objects->{'11A001-167Nabe0001'}->itemnumber}); + ok (not($object1), "Checkout '11A001-167Nabe0001' deleted"); + my $object2 = Koha::Checkouts->find({borrowernumber => $objects->{'11A002-167Nabe0002'}->borrowernumber, + itemnumber => $objects->{'11A002-167Nabe0002'}->itemnumber}); + ok (not($object2), "Checkout '11A002-167Nabe0002' deleted"); +}; + + + +########## LetterTemplateFactory subtests ########## +subtest 't::lib::TestObjects::LetterTemplateFactory' => sub { + my $subtestContext = {}; + ##Create and Delete using dependencies in the $testContext instantiated in previous subtests. + my $f = t::lib::TestObjects::LetterTemplateFactory->new(); + my $hashLT = {letter_id => 'circulation-ODUE1-CPL-print', + module => 'circulation', + code => 'ODUE1', + branchcode => 'CPL', + name => 'Notice1', + is_html => undef, + title => 'Notice1', + message_transport_type => 'print', + content => 'Barcode: <>, bring it back!', + }; + my $objects = $f->createTestGroup([ + $hashLT, + ], undef, undef, undef, undef); + + my $letterTemplate = Koha::LetterTemplates->find($hashLT); + is($objects->{'circulation-ODUE1-CPL-print'}->name, $letterTemplate->name, "LetterTemplate 'circulation-ODUE1-CPL-print'"); + + #Delete them + $f->deleteTestGroup($objects); + $letterTemplate = Koha::LetterTemplates->find($hashLT); + ok(not(defined($letterTemplate)), "LetterTemplate 'circulation-ODUE1-CPL-print' deleted"); +}; + + + +########## Global test context subtests ########## +subtest 't::lib::TestObjects::ObjectFactory clearing global test context' => sub { + my $object11A001 = Koha::Borrowers->find({cardnumber => '11A001'}); + ok ($object11A001, "Global Borrower '11A001' exists"); + my $object11A002 = Koha::Borrowers->find({cardnumber => '11A002'}); + ok ($object11A002, "Global Borrower '11A002' exists"); + + my $object1 = Koha::Items->find({barcode => '167Nabe0001'}); + ok ($object1, "Global Item '167Nabe0001' exists"); + my $object2 = Koha::Items->find({barcode => '167Nabe0002'}); + ok ($object2, "Global Item '167Nabe0002' exists"); + my $object3 = Koha::Biblios->find({title => 'I wish I met your mother', author => "Pertti Kurikka"}); + ok ($object2, "Global Biblio 'I wish I met your mother' exists"); + + t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext); + + $object11A001 = Koha::Borrowers->find({cardnumber => '11A001'}); + ok (not($object11A001), "Global Borrower '11A001' deleted"); + $object11A002 = Koha::Borrowers->find({cardnumber => '11A002'}); + ok (not($object11A002), "Global Borrower '11A002' deleted"); + + $object1 = Koha::Items->find({barcode => '167Nabe0001'}); + ok (not($object1), "Global Item '167Nabe0001' deleted"); + $object2 = Koha::Items->find({barcode => '167Nabe0002'}); + ok (not($object2), "Global Item '167Nabe0002' deleted"); + $object3 = Koha::Biblios->find({title => 'I wish I met your mother', author => "Pertti Kurikka"}); + ok (not($object2), "Global Biblio 'I wish I met your mother' deleted"); +}; + + + +done_testing(); + +1; --