Bugzilla – Attachment 42112 Details for
Bug 14698
AtomicUpdater - Keeps track of which updates have been applied to a database
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 14698 - AtomicUpdater - Keeps track of which updates have been applied to a database
Bug-14698---AtomicUpdater---Keeps-track-of-which-u.patch (text/plain), 34.67 KB, created by
Olli-Antti Kivilahti
on 2015-08-31 11:07:57 UTC
(
hide
)
Description:
Bug 14698 - AtomicUpdater - Keeps track of which updates have been applied to a database
Filename:
MIME Type:
Creator:
Olli-Antti Kivilahti
Created:
2015-08-31 11:07:57 UTC
Size:
34.67 KB
patch
obsolete
>From a8da178c3e9abd1cd9673510f541dbbbbb190ddc Mon Sep 17 00:00:00 2001 >From: Olli-Antti Kivilahti <olli-antti.kivilahti@jns.fi> >Date: Thu, 20 Aug 2015 14:10:02 +0300 >Subject: [PATCH] Bug 14698 - AtomicUpdater - Keeps track of which updates have > been applied to a database > >When deploying production databases to test environments, it is imperative to >keep track of which database changes have been applied. > >When one is running, in production, features that require DB changes, and want >to add more features which need more DB changes, keeping track of which updates >have been applied is challenging. >After several cycles of upgrade-deploy, with multiple atomicupdate-scripts >piling to the atomicupdates/-directory, it is impossible to easily distinguish >which updates have been applied and which are not. > >Rerunning the same update scripts again and >again causes lots of noise in the upgrade log and hides real issues from being >detected. >Also repeatedly running upgrade scripts might cause bad side effects which are >potentially hard to repair. > >This feature adds a script atomicupdate.pl which runs all atomicupdate/* scripts >and .sqls and logs the event to the koha.atomicupdates-table. >On subsequent runs of atomicupdate.pl, the already deployed upgrades are >skipped, greatly reducing the unnecessary clutter and risk of upgrading. > >You can also remove existing log entries to allow rerunning the same upgrade >script again, list all applied upgrades and show pending updates. > >Unit tests included. >--- > C4/Installer/PerlDependencies.pm | 5 + > Koha/AtomicUpdate.pm | 121 +++++++++++ > Koha/AtomicUpdater.pm | 223 +++++++++++++++++++++ > installer/data/mysql/atomicupdate.pl | 96 +++++++++ > .../mysql/atomicupdate/Bug14698-AtomicUpdater.pl | 36 ++++ > installer/data/mysql/kohastructure.sql | 14 ++ > t/db_dependent/Koha/AtomicUpdater.t | 200 ++++++++++++++++++ > t/lib/TestObjects/AtomicUpdateFactory.pm | 105 ++++++++++ > t/lib/TestObjects/ObjectFactory.pm | 5 + > t/lib/TestObjects/objectFactories.t | 39 ++++ > 10 files changed, 844 insertions(+) > create mode 100644 Koha/AtomicUpdate.pm > create mode 100644 Koha/AtomicUpdater.pm > create mode 100644 installer/data/mysql/atomicupdate.pl > create mode 100644 installer/data/mysql/atomicupdate/Bug14698-AtomicUpdater.pl > create mode 100644 t/db_dependent/Koha/AtomicUpdater.t > create mode 100644 t/lib/TestObjects/AtomicUpdateFactory.pm > >diff --git a/C4/Installer/PerlDependencies.pm b/C4/Installer/PerlDependencies.pm >index d052fde..189bf77 100644 >--- a/C4/Installer/PerlDependencies.pm >+++ b/C4/Installer/PerlDependencies.pm >@@ -232,6 +232,11 @@ our $PERL_DEPS = { > 'min_ver' => '0.45', > # Also needed for our use of PDF::Reuse > }, >+ 'Data::Format::Pretty::Console' => { >+ 'usage' => 'Core', >+ 'required' => '1', >+ 'min_ver' => '0.34', >+ }, > 'DateTime' => { > 'usage' => 'Core', > 'required' => '1', >diff --git a/Koha/AtomicUpdate.pm b/Koha/AtomicUpdate.pm >new file mode 100644 >index 0000000..92fbbff >--- /dev/null >+++ b/Koha/AtomicUpdate.pm >@@ -0,0 +1,121 @@ >+package Koha::AtomicUpdate; >+ >+# Copyright Open Source Freedom Fighters >+# >+# 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 File::Basename; >+ >+use Koha::Database; >+ >+use base qw(Koha::Object); >+ >+use Koha::Exception::BadParameter; >+ >+sub type { >+ return 'Atomicupdate'; >+} >+ >+=head @allowedIssueIdentifierPrefixes >+Define the prefixes you want to attach to your atomicupdate filenames here. >+This could be a syspref or in KOHA_CONF, but it is rather easy to just add more >+generally used issue number prefixes here. >+Nobody wants more sysprefs. >+=cut >+ >+my @allowedIssueIdentifierPrefixes = ( >+ 'Bug', >+ '#', >+); >+ >+sub new { >+ my ($class, $params) = @_; >+ $class->_validateParams($params); >+ >+ my $self = {}; >+ bless($self, $class); >+ $self->set($params); >+ return $self; >+} >+ >+sub _validateParams { >+ my ($class, $params) = @_; >+ >+ my @mandatoryParams = ('filename'); >+ foreach my $mp (@mandatoryParams) { >+ Koha::Exception::BadParameter->throw( >+ error => "$class->_validateParams():> Param '$mp' must be given.") >+ unless($params->{$mp}); >+ } >+ $params->{filename} = $class->_validateFilename($params->{filename}); >+ >+ $params->{issue_id} = $class->_getIssueIdentifier($params->{issue_id} || $params->{filename}); >+} >+ >+=head _validateFilename >+ >+Makes sure the given file is a valid AtomicUpdate-script. >+Currently simply checks for naming convention and file suffix. >+ >+NAMING CONVENTION: >+ Filename must contain one of the unique issue identifier prefixes from this >+ list @allowedIssueIdentifierPrefixes immediately followed by the numeric >+ id of the issue, optionally separated by any of the following [ :-] >+ Eg. Bug-45453, #102, #:53 >+ >+@PARAM1 String, filename of validatable file, excluding path. >+@RETURNS String, the koha.atomicupdates.filename if the given file is considered a well formed update script. >+ Removes the full path if present and returns only the filename component. >+ >+@THROWS Koha::Exception::File, if the given file doesn't have a proper naming convention >+ >+=cut >+ >+sub _validateFilename { >+ my ($self, $fileName) = @_; >+ >+ Koha::Exception::File->throw(error => __PACKAGE__."->_validateFilename():> Filename '$fileName' has unknown suffix") >+ unless $fileName =~ /\.(sql|perl|pl)$/; #skip other files >+ >+ $fileName = File::Basename::basename($fileName); >+ >+ return $fileName; >+} >+ >+=head _getIssueIdentifier >+ >+Extracts the unique issue identifier from the atomicupdate DB upgrade script. >+ >+@PARAM1 String, filename of validatable file, excluding path. >+@RETURNS String, The unique issue identifier >+ >+@THROWS Koha::Exception::Parse, if the unique identifier couldn't be parsed. >+=cut >+ >+sub _getIssueIdentifier { >+ my ($self, $fileName) = @_; >+ >+ foreach my $prefix (@allowedIssueIdentifierPrefixes) { >+ if ($fileName =~ m/$prefix[ -:]*?(\d+)/) { >+ return "$prefix$1"; >+ } >+ } >+ Koha::Exception::Parse->throw(error => __PACKAGE__."->_getIssueIdentifier($fileName):> couldn't parse the unique issue identifier from filename using allowed prefixes '@allowedIssueIdentifierPrefixes'"); >+} >+ >+1; >diff --git a/Koha/AtomicUpdater.pm b/Koha/AtomicUpdater.pm >new file mode 100644 >index 0000000..1a9aafd >--- /dev/null >+++ b/Koha/AtomicUpdater.pm >@@ -0,0 +1,223 @@ >+package Koha::AtomicUpdater; >+ >+# Copyright Open Source Freedom Fighters >+# >+# 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 Try::Tiny; >+use Data::Format::Pretty::Console qw(format_pretty); >+ >+use Koha::Database; >+use Koha::Cache; >+use Koha::AtomicUpdate; >+ >+use base qw(Koha::Objects); >+ >+use Koha::Exception::File; >+use Koha::Exception::Parse; >+use Koha::Exception::BadParameter; >+ >+sub type { >+ return 'Atomicupdate'; >+} >+ >+sub object_class { >+ return 'Koha::AtomicUpdate'; >+} >+ >+sub _get_castable_unique_columns { >+ return ['atomicupdate_id']; >+} >+ >+sub new { >+ my ($class, $params) = @_; >+ >+ my $cache = Koha::Cache->new(); >+ my $self = $cache->get_from_cache('Koha::AtomicUpdater') || {}; >+ bless($self, $class); >+ >+ $self->{verbose} = $params->{verbose} || $self->{verbose} || 0; >+ $self->{scriptDir} = $params->{scriptDir} || $self->{scriptDir} || C4::Context->config('intranetdir') . '/installer/data/mysql/atomicupdate/'; >+ >+ return $self; >+} >+ >+=head getAtomicUpdates >+ >+ my $atomicUpdates = $atomicUpdater->getAtomicUpdates(); >+ >+Gets all the AtomicUpdate-objects in the DB. This result should be Koha::Cached. >+@RETURNS ARRAYRef of Koha::AtomicUpdate-objects. >+=cut >+ >+sub getAtomicUpdates { >+ my ($self) = @_; >+ >+ my @au = $self->search({}); >+ my %au; #HASHify the AtomicUpdate-objects for easy searching. >+ foreach my $au (@au) { >+ $au{$au->filename} = $au; >+ } >+ return \%au; >+} >+ >+sub addAtomicUpdate { >+ my ($self, $params) = @_; >+ print "Adding atomicupdate '".$params->{issue_id}."'\n" if $self->{verbose} > 2; >+ >+ my $atomicupdate = Koha::AtomicUpdate->new($params); >+ $atomicupdate->store(); >+ $atomicupdate = $self->find({issue_id => $atomicupdate->issue_id}); >+ return $atomicupdate; >+} >+ >+sub removeAtomicUpdate { >+ my ($self, $issueId) = @_; >+ print "Deleting atomicupdate '$issueId'\n" if $self->{verbose} > 2; >+ >+ my $atomicupdate = $self->find({issue_id => $issueId}); >+ if ($atomicupdate) { >+ $atomicupdate->delete; >+ print "Deleted atomicupdate '$issueId'\n" if $self->{verbose} > 2; >+ } >+ else { >+ Koha::Exception::BadParameter->throw(error => __PACKAGE__."->removeIssueFromLog():> No such Issue '$issueId' stored to the atomicupdates-table"); >+ } >+} >+ >+sub listToConsole { >+ my ($self) = @_; >+ my @stringBuilder; >+ >+ my @atomicupdates = $self->search({}); >+ foreach my $au (@atomicupdates) { >+ push @stringBuilder, $au->unblessed(); >+ } >+ return Data::Format::Pretty::Console::format_pretty(\@stringBuilder); >+} >+ >+sub listPendingToConsole { >+ my ($self) = @_; >+ my @stringBuilder; >+ >+ my $atomicUpdates = $self->getPendingAtomicUpdates(); >+ foreach my $key (sort keys %$atomicUpdates) { >+ my $au = $atomicUpdates->{$key}; >+ push @stringBuilder, $au->unblessed(); >+ } >+ return Data::Format::Pretty::Console::format_pretty(\@stringBuilder); >+} >+ >+sub getPendingAtomicUpdates { >+ my ($self) = @_; >+ >+ my %pendingAtomicUpdates; >+ my $atomicupdateFiles = $self->_getValidAtomicUpdateScripts(); >+ my $atomicUpdatesDeployed = $self->getAtomicUpdates(); >+ foreach my $key (keys(%$atomicupdateFiles)) { >+ my $au = $atomicupdateFiles->{$key}; >+ unless ($atomicUpdatesDeployed->{$au->filename}) { >+ #This script hasn't been deployed. >+ $pendingAtomicUpdates{$au->filename} = $au; >+ } >+ } >+ return \%pendingAtomicUpdates; >+} >+ >+=head applyAtomicUpdates >+ >+ my $atomicUpdater = Koha::AtomicUpdater->new(); >+ my $appliedAtomicupdates = $atomicUpdater->applyAtomicUpdates(); >+ >+Checks the atomicupdates/-directory for any not-applied update scripts and >+runs them. >+ >+@RETURNS ARRAYRef of Koha::AtomicUpdate-objects deployed on this run >+=cut >+ >+sub applyAtomicUpdates { >+ my ($self) = @_; >+ >+ my %appliedUpdates; >+ >+ my $atomicUpdates = $self->getPendingAtomicUpdates(); >+ foreach my $key ( keys %$atomicUpdates ) { >+ my $atomicUpdate = $atomicUpdates->{$key}; >+ my $filename = $atomicUpdate->filename; >+ print "Looking at file '$filename'\n" if $self->{verbose} > 2; >+ >+ if ( $filename =~ /\.sql$/ ) { >+ my $installer = C4::Installer->new(); >+ my $rv = $installer->load_sql( $self->{scriptDir}.'/'.$filename ) ? 0 : 1; >+ } elsif ( $filename =~ /\.(perl|pl)$/ ) { >+ do $self->{scriptDir}.'/'.$filename; >+ } >+ >+ $atomicUpdate->store(); >+ $appliedUpdates{$filename} = $atomicUpdate; >+ print "File '$filename' applied" if $self->{verbose} > 2; >+ } >+ >+ return \%appliedUpdates; >+} >+ >+=head _getValidAtomicUpdateScripts >+ >+@RETURNS HASHRef of Koha::AtomicUpdate-objects, of all the files >+ in the atomicupdates/-directory that can be considered valid. >+ Validity is currently conforming to the naming convention. >+ Keys are the filename excluding the full path. >+ Eg. {'Bug8584-FoundLeBug.pl' => Koha::AtomicUpdate, >+ ... >+ } >+=cut >+ >+sub _getValidAtomicUpdateScripts { >+ my ($self) = @_; >+ >+ my %atomicUpdates; >+ opendir( my $dirh, $self->{scriptDir} ); >+ foreach my $file ( sort readdir $dirh ) { >+ print "Looking at file $file\n" if $self->{verbose} > 2; >+ >+ my $atomicUpdate; >+ try { >+ $atomicUpdate = Koha::AtomicUpdate->new({filename => $file}); >+ } catch { >+ if (blessed($_)) { >+ if ($_->isa('Koha::Exception::File')) { >+ #We can ignore filename validation issues, since the directory has >+ #loads of other types of files as well. Like README . .. >+ } >+ else { >+ $_->rethrow(); >+ } >+ } >+ else { >+ die $_; #Rethrow the unknown Exception >+ } >+ }; >+ next unless $atomicUpdate; >+ >+ $atomicUpdates{$file} = $atomicUpdate; >+ } >+ return \%atomicUpdates; >+} >+ >+1; >diff --git a/installer/data/mysql/atomicupdate.pl b/installer/data/mysql/atomicupdate.pl >new file mode 100644 >index 0000000..5077174 >--- /dev/null >+++ b/installer/data/mysql/atomicupdate.pl >@@ -0,0 +1,96 @@ >+#!/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 Getopt::Long; >+ >+use C4::Context; >+ >+use Koha::AtomicUpdater; >+ >+my $verbose = 0; >+my $help = 0; >+my $apply = 0; >+my $remove = ''; >+my $insert = ''; >+my $list = 0; >+my $pending = 0; >+my $directory = ''; >+ >+GetOptions( >+ 'v|verbose:i' => \$verbose, >+ 'h|help' => \$help, >+ 'a|apply' => \$apply, >+ 'd|directory:s' => \$directory, >+ 'r|remove:s' => \$remove, >+ 'i|insert:s' => \$insert, >+ 'l|list' => \$list, >+ 'p|pending' => \$pending, >+); >+ >+my $usage = << 'ENDUSAGE'; >+ >+Runs all the atomicupdate-scripts and sql in the atomicupdates-directory. >+Checks from koha.database_updates if the update has already been applied. >+ >+Also acts as a gateway to CRUD the koha.database_updates-table to easily remove >+existing upgrade logs. >+ >+ -v --verbose Integer, 1 is not so verbose, 3 is maximally verbose. >+ -h --help Flag, This nice help! >+ -a --apply Flag, Apply all the pending atomicupdates from the >+ atomicupdates-directory. >+ -d --directory Path, From which directory to look for atomicupdate-scripts. >+ Defaults to '$KOHA_PATH/installer/data/mysql/atomicupdate/' >+ -r --remove String, Remove the upgrade entry from koha.database_updates >+ eg. --remove "Bug71337" >+ -i --insert Path, Add an upgrade log entry for the given atomicupdate-file. >+ Useful to revert an accidental --remove -operation or for >+ testing. >+ eg. -i installer/data/mysql/atomicupdate/Bug5453-Example.pl >+ -l --list Flag, List all entries in the koha.database_updates-table. >+ This typically means all applied atomicupdates. >+ -p --pending Flag, List all pending atomicupdates from the >+ atomicupdates-directory. >+ >+ENDUSAGE >+ >+if ( $help ) { >+ print $usage; >+ exit; >+} >+ >+my $atomicupdater = Koha::AtomicUpdater->new({verbose => $verbose}); >+ >+if ($remove) { >+ $atomicupdater->removeAtomicUpdate($remove); >+} >+if ($insert) { >+ $atomicupdater->addAtomicUpdate({filename => $insert}); >+} >+if ($list) { >+ print $atomicupdater->listToConsole(); >+} >+if ($pending) { >+ print $atomicupdater->listPendingToConsole(); >+} >+if ($apply) { >+ $atomicupdater->applyAtomicUpdates(); >+} >diff --git a/installer/data/mysql/atomicupdate/Bug14698-AtomicUpdater.pl b/installer/data/mysql/atomicupdate/Bug14698-AtomicUpdater.pl >new file mode 100644 >index 0000000..177f150 >--- /dev/null >+++ b/installer/data/mysql/atomicupdate/Bug14698-AtomicUpdater.pl >@@ -0,0 +1,36 @@ >+#!/usr/bin/perl >+ >+# Copyright Open Source Freedom Fighters >+# >+# 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 C4::Context; >+ >+my $dbh = C4::Context->dbh(); >+ >+$dbh->do(" >+CREATE TABLE `atomicupdates` ( >+ `atomicupdate_id` int(11) unsigned NOT NULL auto_increment, >+ `issue_id` varchar(20) NOT NULL, >+ `filename` varchar(30) NOT NULL, >+ `modification_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, >+ PRIMARY KEY (`atomicupdate_id`), >+ UNIQUE KEY `origincode` (`issue_id`) >+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; >+"); >+$dbh->do("INSERT INTO atomicupdates (issue_id, filename) VALUES ('Bug14698', 'Bug14698-AtomicUpdater.pl')"); >+ >+print "Upgrade to Bug 14698 - AtomicUpdater - Keeps track of which updates have been applied to a database done\n"; >diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql >index fba99ac..006495b 100644 >--- a/installer/data/mysql/kohastructure.sql >+++ b/installer/data/mysql/kohastructure.sql >@@ -1801,6 +1801,20 @@ CREATE TABLE `printers_profile` ( > ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; > > -- >+-- Table structure for table `atomicupdates` >+-- >+ >+DROP TABLE IF EXISTS `atomicupdates`; >+CREATE TABLE `atomicupdates` ( >+ `atomicupdate_id` int(11) unsigned NOT NULL auto_increment, >+ `issue_id` varchar(20) NOT NULL, >+ `filename` varchar(128) NOT NULL, >+ `modification_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, >+ PRIMARY KEY (`atomicupdate_id`), >+ UNIQUE KEY `atomic_issue_id` (`issue_id`) >+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; >+ >+-- > -- Table structure for table `repeatable_holidays` > -- > >diff --git a/t/db_dependent/Koha/AtomicUpdater.t b/t/db_dependent/Koha/AtomicUpdater.t >new file mode 100644 >index 0000000..436086f >--- /dev/null >+++ b/t/db_dependent/Koha/AtomicUpdater.t >@@ -0,0 +1,200 @@ >+#!/usr/bin/perl >+ >+# Copyright 2015 Open Source Freedom Fighters >+# >+# 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, see <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+use Test::More; >+use Try::Tiny; >+use Encode; >+ >+use t::lib::TestObjects::ObjectFactory; >+use t::lib::TestObjects::AtomicUpdateFactory; >+use t::lib::TestObjects::FileFactory; >+use Koha::AtomicUpdater; >+ >+my $testContext = {}; >+my $atomicupdates = t::lib::TestObjects::AtomicUpdateFactory->createTestGroup([ >+ {issue_id => 'Bug12', >+ filename => 'Bug12-WatchExMachinaYoullLikeIt.pl'}, >+ {issue_id => 'Bug14', >+ filename => 'Bug14-ReturnOfZorro.perl'}, >+ {issue_id => '#14', >+ filename => '#14-RobotronInDanger.sql'}, >+ {issue_id => '#15', >+ filename => '#15-ILikedPrometheusButAlienWasBetter.pl'}, >+ ], undef, $testContext); >+ >+subtest "List all deployed atomicupdates" => \&listAtomicUpdates; >+sub listAtomicUpdates { >+ eval { >+ my $atomicUpdater = Koha::AtomicUpdater->new(); >+ my $text = $atomicUpdater->listToConsole(); >+ print $text; >+ >+ ok($text =~ m/Bug12-WatchExMachinaYoullLik/, >+ "Bug12-WatchExMachinaYoullLikeIt"); >+ ok($text =~ m/Bug14-ReturnOfZorro.perl/, >+ "Bug14-ReturnOfZorro"); >+ ok($text =~ m/#14-RobotronInDanger.sql/, >+ "#14-RobotronInDanger"); >+ ok($text =~ m/#15-ILikedPrometheusButAli/, >+ "#15-ILikedPrometheusButAlienWasBetter"); >+ >+ }; >+ if ($@) { >+ ok(0, $@); >+ } >+} >+ >+subtest "Delete an atomicupdate entry" => \&deleteAtomicupdate; >+sub deleteAtomicupdate { >+ eval { >+ my $atomicUpdater = Koha::AtomicUpdater->new(); >+ my $atomicupdate = $atomicUpdater->cast($atomicupdates->{Bug12}->id); >+ ok($atomicupdate, >+ "AtomicUpdate '".$atomicupdates->{Bug12}->issue_id."' exists prior to deletion"); >+ >+ $atomicUpdater->removeAtomicUpdate($atomicupdate->issue_id); >+ $atomicupdate = $atomicUpdater->find($atomicupdates->{Bug12}->id); >+ ok(not($atomicupdate), >+ "AtomicUpdate '".$atomicupdates->{Bug12}->issue_id."' deleted"); >+ >+ }; >+ if ($@) { >+ ok(0, $@); >+ } >+} >+ >+subtest "Insert an atomicupdate entry" => \&insertAtomicupdate; >+sub insertAtomicupdate { >+ eval { >+ my $atomicUpdater = Koha::AtomicUpdater->new(); >+ my $subtestContext = {}; >+ my $atomicupdates = t::lib::TestObjects::AtomicUpdateFactory->createTestGroup([ >+ {issue_id => 'Bug15', >+ filename => 'Bug15-Inserted.pl'}, >+ ], undef, $subtestContext, $testContext); >+ my $atomicupdate = $atomicUpdater->find({issue_id => 'Bug15'}); >+ ok($atomicupdate, >+ "Bug15-Inserted.pl"); >+ >+ t::lib::TestObjects::ObjectFactory->tearDownTestContext($subtestContext); >+ >+ $atomicupdate = $atomicUpdater->find({issue_id => 'Bug15'}); >+ ok(not($atomicupdate), >+ "Bug15-Inserted.pl deleted"); >+ }; >+ if ($@) { >+ ok(0, $@); >+ } >+} >+ >+subtest "List pending atomicupdates" => \&listPendingAtomicupdates; >+sub listPendingAtomicupdates { >+ my ($atomicUpdater, $files, $text, $atomicupdates); >+ my $subtestContext = {}; >+ eval { >+ ##Test adding update scripts and deploy them, confirm that no pending scripts detected >+ $files = t::lib::TestObjects::FileFactory->createTestGroup([ >+ { filepath => 'atomicupdate/', >+ filename => '#911-WhoYouGonnaCall.pl', >+ content => '$ENV{ATOMICUPDATE_TESTS} = 1;',}, >+ { filepath => 'atomicupdate/', >+ filename => 'Bug911-WhatchaGonnaDo.pl', >+ content => '$ENV{ATOMICUPDATE_TESTS}++;',}, >+ { filepath => 'atomicupdate/', >+ filename => 'Bug112-LapinlahdenLinnut.pl', >+ content => '$ENV{ATOMICUPDATE_TESTS}++;',}, >+ ], >+ undef, $subtestContext, $testContext); >+ $atomicUpdater = Koha::AtomicUpdater->new({ >+ scriptDir => $files->{'#911-WhoYouGonnaCall.pl'}->dirname() >+ }); >+ >+ $text = $atomicUpdater->listPendingToConsole(); >+ print $text; >+ >+ ok($text =~ m/#911-WhoYouGonnaCall.pl/, >+ "#911-WhoYouGonnaCall is pending"); >+ ok($text =~ m/Bug911-WhatchaGonnaDo.pl/, >+ "Bug911-WhatchaGonnaDo is pending"); >+ ok($text =~ m/Bug112-LapinlahdenLinnut.pl/, >+ 'Bug112-LapinlahdenLinnut is pending'); >+ >+ $atomicupdates = $atomicUpdater->applyAtomicUpdates(); >+ t::lib::TestObjects::AtomicUpdateFactory->addToContext($atomicupdates, undef, $subtestContext, $testContext); #Keep track of changes >+ >+ is($atomicupdates->{'#911-WhoYouGonnaCall.pl'}->issue_id, >+ '#911', >+ "#911-WhoYouGonnaCall.pl deployed"); >+ is($atomicupdates->{'Bug112-LapinlahdenLinnut.pl'}->issue_id, >+ 'Bug112', >+ 'Bug112-LapinlahdenLinnut.pl deployed'); >+ is($atomicupdates->{'Bug911-WhatchaGonnaDo.pl'}->issue_id, >+ 'Bug911', >+ "Bug911-WhatchaGonnaDo.pl deployed"); >+ >+ ##Test adding scripts to the atomicupdates directory and how we deal with such change. >+ $files = t::lib::TestObjects::FileFactory->createTestGroup([ >+ { filepath => 'atomicupdate/', >+ filename => '#53-PlaceToBe.pl', >+ content => '$ENV{ATOMICUPDATE_TESTS}++;',}, >+ { filepath => 'atomicupdate/', >+ filename => '#54-KohaConInFinlandNextYear.pl', >+ content => '$ENV{ATOMICUPDATE_TESTS}++;',}, >+ { filepath => 'atomicupdate/', >+ filename => '#55-Fiftyfive.pl', >+ content => '$ENV{ATOMICUPDATE_TESTS}++;',}, >+ ], >+ undef, $subtestContext, $testContext); >+ >+ $text = $atomicUpdater->listPendingToConsole(); >+ print $text; >+ >+ ok($text =~ m/#53-PlaceToBe.pl/, >+ "#53-PlaceToBe.pl is pending"); >+ ok($text =~ m/#54-KohaConInFinlandNextYear.pl/, >+ "#54-KohaConInFinlandNextYear.pl is pending"); >+ ok($text =~ m/#55-Fiftyfive.pl/u, >+ '#55-Fiftyfive.pl'); >+ >+ $atomicupdates = $atomicUpdater->applyAtomicUpdates(); >+ t::lib::TestObjects::AtomicUpdateFactory->addToContext($atomicupdates, undef, $subtestContext, $testContext); #Keep track of changes >+ >+ is($atomicupdates->{'#53-PlaceToBe.pl'}->issue_id, >+ '#53', >+ "#53-PlaceToBe.pl deployed"); >+ is($atomicupdates->{'#54-KohaConInFinlandNextYear.pl'}->issue_id, >+ '#54', >+ '#54-KohaConInFinlandNextYear.pl deployed'); >+ is($atomicupdates->{'#55-Fiftyfive.pl'}->issue_id, >+ '#55', >+ "#55-Fiftyfive.pl deployed"); >+ >+ is($ENV{ATOMICUPDATE_TESTS}, >+ 6, >+ "All configured AtomicUpdates deployed"); >+ }; >+ if ($@) { >+ ok(0, $@); >+ } >+ t::lib::TestObjects::AtomicUpdateFactory->tearDownTestContext($subtestContext); >+} >+ >+t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext); >+done_testing; >\ No newline at end of file >diff --git a/t/lib/TestObjects/AtomicUpdateFactory.pm b/t/lib/TestObjects/AtomicUpdateFactory.pm >new file mode 100644 >index 0000000..4aff6f1 >--- /dev/null >+++ b/t/lib/TestObjects/AtomicUpdateFactory.pm >@@ -0,0 +1,105 @@ >+package t::lib::TestObjects::AtomicUpdateFactory; >+ >+# 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::AtomicUpdater; >+use Koha::Database; >+ >+use Koha::Exception::UnknownProgramState; >+ >+use base qw(t::lib::TestObjects::ObjectFactory); >+ >+sub getDefaultHashKey { >+ return 'issue_id'; >+} >+sub getObjectType { >+ return 'Koha::AtomicUpdate'; >+} >+ >+=head t::lib::TestObjects::createTestGroup >+ >+ my $atomicupdates = t::lib::TestObjects::AtomicUpdateFactory->createTestGroup([ >+ {'issue_id' => 'Bug3432', >+ 'filename' => 'Bug3432-RavingRabbitsMayhem', >+ 'modification_time' => '2015-01-02 15:59:32', >+ }, >+ ], undef, $testContext1, $testContext2, $testContext3); >+ >+Calls Koha::AtomicUpdater to add a Koha::AtomicUpdate object to DB. >+ >+The HASH is keyed with the 'koha.atomicupdates.issue_id', or the given $hashKey. >+ >+There is a duplication check to first look for atomicupdate-rows with the same 'issue_id'. >+If a matching atomicupdate is found, then we use the existing Record instead of adding a new one. >+ >+@RETURNS HASHRef of Koha::AtomicUpdate-objects >+ >+See t::lib::TestObjects::ObjectFactory for more documentation >+=cut >+ >+sub handleTestObject { >+ my ($class, $object, $stashes) = @_; >+ >+ ##First see if the given Record already exists in the DB. For testing purposes we use the isbn as the UNIQUE identifier. >+ my $atomicupdate = Koha::AtomicUpdater->find({issue_id => $object->{issue_id}}); >+ unless ($atomicupdate) { >+ my $atomicupdater = Koha::AtomicUpdater->new(); >+ $atomicupdate = $atomicupdater->addAtomicUpdate($object); >+ } >+ >+ Koha::Exception::UnknownProgramState->throw(error => "$class->handleTestObject():> Cannot create a new object\n$@\n") >+ unless $atomicupdate; >+ >+ return $atomicupdate; >+} >+ >+=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, $object, $hashKey) = @_; >+ >+ $object->{issue_id} = 'BugRancidacid' unless $object->{issue_id}; >+ $object->{filename} = 'BugRancidacid-LaboratoryExperimentsGoneSour' unless $object->{filename}; >+ >+ $self->SUPER::validateAndPopulateDefaultValues($object, $hashKey); >+} >+ >+sub deleteTestGroup { >+ my ($class, $objects) = @_; >+ >+ while( my ($key, $object) = each %$objects) { >+ my $atomicupdate = Koha::AtomicUpdater->cast($object); >+ eval { >+ $atomicupdate->delete(); >+ }; >+ if ($@) { >+ warn "$class->deleteTestGroup():> Error hapened: $@\n"; >+ } >+ } >+} >+ >+1; >diff --git a/t/lib/TestObjects/ObjectFactory.pm b/t/lib/TestObjects/ObjectFactory.pm >index e4f6441..fb6de71 100644 >--- a/t/lib/TestObjects/ObjectFactory.pm >+++ b/t/lib/TestObjects/ObjectFactory.pm >@@ -166,6 +166,11 @@ sub tearDownTestContext { > t::lib::TestObjects::BiblioFactory->deleteTestGroup($stash->{biblio}); > delete $stash->{biblio}; > } >+ if ($stash->{atomicupdate}) { >+ require t::lib::TestObjects::AtomicUpdateFactory; >+ t::lib::TestObjects::AtomicUpdateFactory->deleteTestGroup($stash->{atomicupdate}); >+ delete $stash->{atomicupdate}; >+ } > if ($stash->{borrower}) { > require t::lib::TestObjects::BorrowerFactory; > t::lib::TestObjects::BorrowerFactory->deleteTestGroup($stash->{borrower}); >diff --git a/t/lib/TestObjects/objectFactories.t b/t/lib/TestObjects/objectFactories.t >index c6668b9..7a4ef65 100644 >--- a/t/lib/TestObjects/objectFactories.t >+++ b/t/lib/TestObjects/objectFactories.t >@@ -30,6 +30,8 @@ use t::lib::TestObjects::BorrowerFactory; > use Koha::Borrowers; > use t::lib::TestObjects::ItemFactory; > use Koha::Items; >+use t::lib::TestObjects::AtomicUpdateFactory; >+use Koha::AtomicUpdater; > use t::lib::TestObjects::BiblioFactory; > use Koha::Biblios; > use t::lib::TestObjects::CheckoutFactory; >@@ -472,6 +474,43 @@ sub testLetterTemplateFactory { > > > >+########## AtomicUpdateFactory subtests ########## >+subtest 't::lib::TestObjects::AtomicUpdateFactory' => \&testAtomicUpdateFactory; >+sub testAtomicUpdateFactory { >+ my ($atomicUpdater, $atomicupdate); >+ my $subtestContext = {}; >+ ##Create and Delete using dependencies in the $testContext instantiated in previous subtests. >+ my $atomicupdates = t::lib::TestObjects::AtomicUpdateFactory->createTestGroup([ >+ {'issue_id' => 'Bug10', >+ 'filename' => 'Bug10-RavingRabbitsMayhem', >+ 'modification_time' => '2015-01-02 15:59:32',}, >+ {'issue_id' => 'Bug11', >+ 'filename' => 'Bug11-RancidSausages', >+ 'modification_time' => '2015-01-02 15:59:33',}, >+ ], >+ undef, $subtestContext); >+ $atomicUpdater = Koha::AtomicUpdater->new(); >+ $atomicupdate = $atomicUpdater->find({issue_id => $atomicupdates->{Bug10}->issue_id}); >+ is($atomicupdate->issue_id, >+ 'Bug10', >+ "Bug10-RavingRabbitsMayhem created"); >+ $atomicupdate = $atomicUpdater->find({issue_id => $atomicupdates->{Bug11}->issue_id}); >+ is($atomicupdate->issue_id, >+ 'Bug11', >+ "Bug11-RancidSausages created"); >+ >+ t::lib::TestObjects::ObjectFactory->tearDownTestContext($subtestContext); >+ >+ $atomicupdate = $atomicUpdater->find({issue_id => $atomicupdates->{Bug10}->issue_id}); >+ ok(not($atomicupdate), >+ "Bug10-RavingRabbitsMayhem deleted"); >+ $atomicupdate = $atomicUpdater->find({issue_id => $atomicupdates->{Bug11}->issue_id}); >+ ok(not($atomicupdate), >+ "Bug11-RancidSausages created"); >+}; >+ >+ >+ > ########## SystemPreferenceFactory subtests ########## > subtest 't::lib::TestObjects::SystemPreferenceFactory' => \&testSystemPreferenceFactory; > sub testSystemPreferenceFactory { >-- >1.9.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 14698
:
42112
|
42113
|
42385
|
42386
|
42395
|
42398
|
42426
|
42521
|
42523
|
62141
|
64404
|
102899
|
102900
|
102901
|
102902
|
102903