View | Details | Raw Unified | Return to bug 14698
Collapse All | Expand All

(-)a/C4/Installer/PerlDependencies.pm (+5 lines)
Lines 232-237 our $PERL_DEPS = { Link Here
232
        'min_ver'  => '0.45',
232
        'min_ver'  => '0.45',
233
        # Also needed for our use of PDF::Reuse
233
        # Also needed for our use of PDF::Reuse
234
    },
234
    },
235
    'Data::Format::Pretty::Console' => {
236
        'usage'    => 'Core',
237
        'required' => '1',
238
        'min_ver'  => '0.34',
239
    },
235
    'DateTime' => {
240
    'DateTime' => {
236
        'usage'    => 'Core',
241
        'usage'    => 'Core',
237
        'required' => '1',
242
        'required' => '1',
(-)a/Koha/AtomicUpdate.pm (+121 lines)
Line 0 Link Here
1
package Koha::AtomicUpdate;
2
3
# Copyright Open Source Freedom Fighters
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
use Carp;
22
use File::Basename;
23
24
use Koha::Database;
25
26
use base qw(Koha::Object);
27
28
use Koha::Exception::BadParameter;
29
30
sub type {
31
    return 'Atomicupdate';
32
}
33
34
=head @allowedIssueIdentifierPrefixes
35
Define the prefixes you want to attach to your atomicupdate filenames here.
36
This could be a syspref or in KOHA_CONF, but it is rather easy to just add more
37
generally used issue number prefixes here.
38
Nobody wants more sysprefs.
39
=cut
40
41
my @allowedIssueIdentifierPrefixes = (
42
    'Bug',
43
    '#',
44
);
45
46
sub new {
47
    my ($class, $params) = @_;
48
    $class->_validateParams($params);
49
50
    my $self = {};
51
    bless($self, $class);
52
    $self->set($params);
53
    return $self;
54
}
55
56
sub _validateParams {
57
    my ($class, $params) = @_;
58
59
    my @mandatoryParams = ('filename');
60
    foreach my $mp (@mandatoryParams) {
61
        Koha::Exception::BadParameter->throw(
62
            error => "$class->_validateParams():> Param '$mp' must be given.")
63
                unless($params->{$mp});
64
    }
65
    $params->{filename} = $class->_validateFilename($params->{filename});
66
67
    $params->{issue_id} = $class->_getIssueIdentifier($params->{issue_id} || $params->{filename});
68
}
69
70
=head _validateFilename
71
72
Makes sure the given file is a valid AtomicUpdate-script.
73
Currently simply checks for naming convention and file suffix.
74
75
NAMING CONVENTION:
76
    Filename must contain one of the unique issue identifier prefixes from this
77
    list @allowedIssueIdentifierPrefixes immediately followed by the numeric
78
    id of the issue, optionally separated by any of the following [ :-]
79
    Eg. Bug-45453, #102, #:53
80
81
@PARAM1 String, filename of validatable file, excluding path.
82
@RETURNS String, the koha.atomicupdates.filename if the given file is considered a well formed update script.
83
                 Removes the full path if present and returns only the filename component.
84
85
@THROWS Koha::Exception::File, if the given file doesn't have a proper naming convention
86
87
=cut
88
89
sub _validateFilename {
90
    my ($self, $fileName) = @_;
91
92
    Koha::Exception::File->throw(error => __PACKAGE__."->_validateFilename():> Filename '$fileName' has unknown suffix")
93
            unless $fileName =~ /\.(sql|perl|pl)$/;  #skip other files
94
    
95
    $fileName = File::Basename::basename($fileName);
96
97
    return $fileName;
98
}
99
100
=head _getIssueIdentifier
101
102
Extracts the unique issue identifier from the atomicupdate DB upgrade script.
103
104
@PARAM1 String, filename of validatable file, excluding path.
105
@RETURNS String, The unique issue identifier
106
107
@THROWS Koha::Exception::Parse, if the unique identifier couldn't be parsed.
108
=cut
109
110
sub _getIssueIdentifier {
111
    my ($self, $fileName) = @_;
112
113
    foreach my $prefix (@allowedIssueIdentifierPrefixes) {
114
        if ($fileName =~ m/$prefix[ -:]*?(\d+)/) {
115
            return "$prefix$1";
116
        }
117
    }
118
    Koha::Exception::Parse->throw(error => __PACKAGE__."->_getIssueIdentifier($fileName):> couldn't parse the unique issue identifier from filename using allowed prefixes '@allowedIssueIdentifierPrefixes'");
119
}
120
121
1;
(-)a/Koha/AtomicUpdater.pm (+223 lines)
Line 0 Link Here
1
package Koha::AtomicUpdater;
2
3
# Copyright Open Source Freedom Fighters
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
use Carp;
22
use Scalar::Util qw(blessed);
23
use Try::Tiny;
24
use Data::Format::Pretty::Console qw(format_pretty);
25
26
use Koha::Database;
27
use Koha::Cache;
28
use Koha::AtomicUpdate;
29
30
use base qw(Koha::Objects);
31
32
use Koha::Exception::File;
33
use Koha::Exception::Parse;
34
use Koha::Exception::BadParameter;
35
36
sub type {
37
    return 'Atomicupdate';
38
}
39
40
sub object_class {
41
    return 'Koha::AtomicUpdate';
42
}
43
44
sub _get_castable_unique_columns {
45
    return ['atomicupdate_id'];
46
}
47
48
sub new {
49
    my ($class, $params) = @_;
50
51
    my $cache = Koha::Cache->new();
52
    my $self = $cache->get_from_cache('Koha::AtomicUpdater') || {};
53
    bless($self, $class);
54
55
    $self->{verbose} = $params->{verbose} || $self->{verbose} || 0;
56
    $self->{scriptDir} = $params->{scriptDir} || $self->{scriptDir} || C4::Context->config('intranetdir') . '/installer/data/mysql/atomicupdate/';
57
58
    return $self;
59
}
60
61
=head getAtomicUpdates
62
63
    my $atomicUpdates = $atomicUpdater->getAtomicUpdates();
64
65
Gets all the AtomicUpdate-objects in the DB. This result should be Koha::Cached.
66
@RETURNS ARRAYRef of Koha::AtomicUpdate-objects.
67
=cut
68
69
sub getAtomicUpdates {
70
    my ($self) = @_;
71
72
    my @au = $self->search({});
73
    my %au; #HASHify the AtomicUpdate-objects for easy searching.
74
    foreach my $au (@au) {
75
        $au{$au->filename} = $au;
76
    }
77
    return \%au;
78
}
79
80
sub addAtomicUpdate {
81
    my ($self, $params) = @_;
82
    print "Adding atomicupdate '".$params->{issue_id}."'\n" if $self->{verbose} > 2;
83
84
    my $atomicupdate = Koha::AtomicUpdate->new($params);
85
    $atomicupdate->store();
86
    $atomicupdate = $self->find({issue_id => $atomicupdate->issue_id});
87
    return $atomicupdate;
88
}
89
90
sub removeAtomicUpdate {
91
    my ($self, $issueId) = @_;
92
    print "Deleting atomicupdate '$issueId'\n" if $self->{verbose} > 2;
93
94
    my $atomicupdate = $self->find({issue_id => $issueId});
95
    if ($atomicupdate) {
96
        $atomicupdate->delete;
97
        print "Deleted atomicupdate '$issueId'\n" if $self->{verbose} > 2;
98
    }
99
    else {
100
        Koha::Exception::BadParameter->throw(error => __PACKAGE__."->removeIssueFromLog():> No such Issue '$issueId' stored to the atomicupdates-table");
101
    }
102
}
103
104
sub listToConsole {
105
    my ($self) = @_;
106
    my @stringBuilder;
107
108
    my @atomicupdates = $self->search({});
109
    foreach my $au (@atomicupdates) {
110
        push @stringBuilder, $au->unblessed();
111
    }
112
    return Data::Format::Pretty::Console::format_pretty(\@stringBuilder);
113
}
114
115
sub listPendingToConsole {
116
    my ($self) = @_;
117
    my @stringBuilder;
118
119
    my $atomicUpdates = $self->getPendingAtomicUpdates();
120
    foreach my $key (sort keys %$atomicUpdates) {
121
        my $au = $atomicUpdates->{$key};
122
        push @stringBuilder, $au->unblessed();
123
    }
124
    return Data::Format::Pretty::Console::format_pretty(\@stringBuilder);
125
}
126
127
sub getPendingAtomicUpdates {
128
    my ($self) = @_;
129
130
    my %pendingAtomicUpdates;
131
    my $atomicupdateFiles = $self->_getValidAtomicUpdateScripts();
132
    my $atomicUpdatesDeployed = $self->getAtomicUpdates();
133
    foreach my $key (keys(%$atomicupdateFiles)) {
134
        my $au = $atomicupdateFiles->{$key};
135
        unless ($atomicUpdatesDeployed->{$au->filename}) {
136
            #This script hasn't been deployed.
137
            $pendingAtomicUpdates{$au->filename} = $au;
138
        }
139
    }
140
    return \%pendingAtomicUpdates;
141
}
142
143
=head applyAtomicUpdates
144
145
    my $atomicUpdater = Koha::AtomicUpdater->new();
146
    my $appliedAtomicupdates = $atomicUpdater->applyAtomicUpdates();
147
148
Checks the atomicupdates/-directory for any not-applied update scripts and
149
runs them.
150
151
@RETURNS ARRAYRef of Koha::AtomicUpdate-objects deployed on this run
152
=cut
153
154
sub applyAtomicUpdates {
155
    my ($self) = @_;
156
157
    my %appliedUpdates;
158
159
    my $atomicUpdates = $self->getPendingAtomicUpdates();
160
    foreach my $key ( keys %$atomicUpdates ) {
161
        my $atomicUpdate = $atomicUpdates->{$key};
162
        my $filename = $atomicUpdate->filename;
163
        print "Looking at file '$filename'\n" if $self->{verbose} > 2;
164
165
        if ( $filename =~ /\.sql$/ ) {
166
            my $installer = C4::Installer->new();
167
            my $rv = $installer->load_sql( $self->{scriptDir}.'/'.$filename ) ? 0 : 1;
168
        } elsif ( $filename =~ /\.(perl|pl)$/ ) {
169
            do $self->{scriptDir}.'/'.$filename;
170
        }
171
172
        $atomicUpdate->store();
173
        $appliedUpdates{$filename} = $atomicUpdate;
174
        print "File '$filename' applied" if $self->{verbose} > 2;
175
    }
176
177
    return \%appliedUpdates;
178
}
179
180
=head _getValidAtomicUpdateScripts
181
182
@RETURNS HASHRef of Koha::AtomicUpdate-objects, of all the files
183
                in the atomicupdates/-directory that can be considered valid.
184
                Validity is currently conforming to the naming convention.
185
                Keys are the filename excluding the full path.
186
                Eg. {'Bug8584-FoundLeBug.pl' => Koha::AtomicUpdate,
187
                     ...
188
                    }
189
=cut
190
191
sub _getValidAtomicUpdateScripts {
192
    my ($self) = @_;
193
194
    my %atomicUpdates;
195
    opendir( my $dirh, $self->{scriptDir} );
196
    foreach my $file ( sort readdir $dirh ) {
197
        print "Looking at file $file\n" if $self->{verbose} > 2;
198
199
        my $atomicUpdate;
200
        try {
201
            $atomicUpdate = Koha::AtomicUpdate->new({filename => $file});
202
        } catch {
203
            if (blessed($_)) {
204
                if ($_->isa('Koha::Exception::File')) {
205
                    #We can ignore filename validation issues, since the directory has
206
                    #loads of other types of files as well. Like README . ..
207
                }
208
                else {
209
                    $_->rethrow();
210
                }
211
            }
212
            else {
213
                die $_; #Rethrow the unknown Exception
214
            }
215
        };
216
        next unless $atomicUpdate;
217
218
        $atomicUpdates{$file} = $atomicUpdate;
219
    }
220
    return \%atomicUpdates;
221
}
222
223
1;
(-)a/installer/data/mysql/atomicupdate.pl (+96 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
#
3
# Copyright Vaara-kirjastot 2015
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
#
20
21
use Modern::Perl;
22
use Getopt::Long;
23
24
use C4::Context;
25
26
use Koha::AtomicUpdater;
27
28
my $verbose = 0;
29
my $help = 0;
30
my $apply = 0;
31
my $remove = '';
32
my $insert = '';
33
my $list = 0;
34
my $pending = 0;
35
my $directory = '';
36
37
GetOptions( 
38
    'v|verbose:i'       => \$verbose,
39
    'h|help'            => \$help,
40
    'a|apply'           => \$apply,
41
    'd|directory:s'     => \$directory,
42
    'r|remove:s'        => \$remove,
43
    'i|insert:s'        => \$insert,
44
    'l|list'            => \$list,
45
    'p|pending'         => \$pending,
46
);
47
48
my $usage = << 'ENDUSAGE';
49
50
Runs all the atomicupdate-scripts and sql in the atomicupdates-directory.
51
Checks from koha.database_updates if the update has already been applied.
52
53
Also acts as a gateway to CRUD the koha.database_updates-table to easily remove
54
existing upgrade logs.
55
56
    -v --verbose        Integer, 1 is not so verbose, 3 is maximally verbose.
57
    -h --help           Flag, This nice help!
58
    -a --apply          Flag, Apply all the pending atomicupdates from the
59
                        atomicupdates-directory.
60
    -d --directory      Path, From which directory to look for atomicupdate-scripts.
61
                        Defaults to '$KOHA_PATH/installer/data/mysql/atomicupdate/'
62
    -r --remove         String, Remove the upgrade entry from koha.database_updates
63
                        eg. --remove "Bug71337"
64
    -i --insert         Path, Add an upgrade log entry for the given atomicupdate-file.
65
                        Useful to revert an accidental --remove -operation or for
66
                        testing.
67
                        eg. -i installer/data/mysql/atomicupdate/Bug5453-Example.pl
68
    -l --list           Flag, List all entries in the koha.database_updates-table.
69
                        This typically means all applied atomicupdates.
70
    -p --pending        Flag, List all pending atomicupdates from the
71
                        atomicupdates-directory.
72
73
ENDUSAGE
74
 
75
if ( $help ) {
76
    print $usage;
77
    exit;
78
}
79
80
my $atomicupdater = Koha::AtomicUpdater->new({verbose => $verbose});
81
82
if ($remove) {
83
    $atomicupdater->removeAtomicUpdate($remove);
84
}
85
if ($insert) {
86
    $atomicupdater->addAtomicUpdate({filename => $insert});
87
}
88
if ($list) {
89
    print $atomicupdater->listToConsole();
90
}
91
if ($pending) {
92
    print $atomicupdater->listPendingToConsole();
93
}
94
if ($apply) {
95
    $atomicupdater->applyAtomicUpdates();
96
}
(-)a/installer/data/mysql/atomicupdate/Bug14698-AtomicUpdater.pl (+36 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright Open Source Freedom Fighters
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use C4::Context;
21
22
my $dbh = C4::Context->dbh();
23
24
$dbh->do("
25
CREATE TABLE `atomicupdates` (
26
  `atomicupdate_id` int(11) unsigned NOT NULL auto_increment,
27
  `issue_id` varchar(20) NOT NULL,
28
  `filename` varchar(30) NOT NULL,
29
  `modification_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
30
  PRIMARY KEY  (`atomicupdate_id`),
31
  UNIQUE KEY `origincode` (`issue_id`)
32
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
33
");
34
$dbh->do("INSERT INTO atomicupdates (issue_id, filename) VALUES ('Bug14698', 'Bug14698-AtomicUpdater.pl')");
35
36
print "Upgrade to Bug 14698 - AtomicUpdater - Keeps track of which updates have been applied to a database done\n";
(-)a/installer/data/mysql/kohastructure.sql (+14 lines)
Lines 1801-1806 CREATE TABLE `printers_profile` ( Link Here
1801
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
1801
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
1802
1802
1803
--
1803
--
1804
-- Table structure for table `atomicupdates`
1805
--
1806
1807
DROP TABLE IF EXISTS `atomicupdates`;
1808
CREATE TABLE `atomicupdates` (
1809
  `atomicupdate_id` int(11) unsigned NOT NULL auto_increment,
1810
  `issue_id` varchar(20) NOT NULL,
1811
  `filename` varchar(128) NOT NULL,
1812
  `modification_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
1813
  PRIMARY KEY  (`atomicupdate_id`),
1814
  UNIQUE KEY `atomic_issue_id` (`issue_id`)
1815
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
1816
1817
--
1804
-- Table structure for table `repeatable_holidays`
1818
-- Table structure for table `repeatable_holidays`
1805
--
1819
--
1806
1820
(-)a/t/db_dependent/Koha/AtomicUpdater.t (+200 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2015 Open Source Freedom Fighters
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Test::More;
22
use Try::Tiny;
23
use Encode;
24
25
use t::lib::TestObjects::ObjectFactory;
26
use t::lib::TestObjects::AtomicUpdateFactory;
27
use t::lib::TestObjects::FileFactory;
28
use Koha::AtomicUpdater;
29
30
my $testContext = {};
31
my $atomicupdates = t::lib::TestObjects::AtomicUpdateFactory->createTestGroup([
32
                           {issue_id => 'Bug12',
33
                            filename => 'Bug12-WatchExMachinaYoullLikeIt.pl'},
34
                           {issue_id => 'Bug14',
35
                            filename => 'Bug14-ReturnOfZorro.perl'},
36
                           {issue_id => '#14',
37
                            filename => '#14-RobotronInDanger.sql'},
38
                           {issue_id => '#15',
39
                            filename => '#15-ILikedPrometheusButAlienWasBetter.pl'},
40
                           ], undef, $testContext);
41
42
subtest "List all deployed atomicupdates" => \&listAtomicUpdates;
43
sub listAtomicUpdates {
44
    eval {
45
    my $atomicUpdater = Koha::AtomicUpdater->new();
46
    my $text = $atomicUpdater->listToConsole();
47
    print $text;
48
49
    ok($text =~ m/Bug12-WatchExMachinaYoullLik/,
50
       "Bug12-WatchExMachinaYoullLikeIt");
51
    ok($text =~ m/Bug14-ReturnOfZorro.perl/,
52
       "Bug14-ReturnOfZorro");
53
    ok($text =~ m/#14-RobotronInDanger.sql/,
54
       "#14-RobotronInDanger");
55
    ok($text =~ m/#15-ILikedPrometheusButAli/,
56
       "#15-ILikedPrometheusButAlienWasBetter");
57
58
    };
59
    if ($@) {
60
        ok(0, $@);
61
    }
62
}
63
64
subtest "Delete an atomicupdate entry" => \&deleteAtomicupdate;
65
sub deleteAtomicupdate {
66
    eval {
67
    my $atomicUpdater = Koha::AtomicUpdater->new();
68
    my $atomicupdate = $atomicUpdater->cast($atomicupdates->{Bug12}->id);
69
    ok($atomicupdate,
70
       "AtomicUpdate '".$atomicupdates->{Bug12}->issue_id."' exists prior to deletion");
71
72
    $atomicUpdater->removeAtomicUpdate($atomicupdate->issue_id);
73
    $atomicupdate = $atomicUpdater->find($atomicupdates->{Bug12}->id);
74
    ok(not($atomicupdate),
75
       "AtomicUpdate '".$atomicupdates->{Bug12}->issue_id."' deleted");
76
77
    };
78
    if ($@) {
79
        ok(0, $@);
80
    }
81
}
82
83
subtest "Insert an atomicupdate entry" => \&insertAtomicupdate;
84
sub insertAtomicupdate {
85
    eval {
86
    my $atomicUpdater = Koha::AtomicUpdater->new();
87
    my $subtestContext = {};
88
    my $atomicupdates = t::lib::TestObjects::AtomicUpdateFactory->createTestGroup([
89
                           {issue_id => 'Bug15',
90
                            filename => 'Bug15-Inserted.pl'},
91
                           ], undef, $subtestContext, $testContext);
92
    my $atomicupdate = $atomicUpdater->find({issue_id => 'Bug15'});
93
    ok($atomicupdate,
94
       "Bug15-Inserted.pl");
95
96
    t::lib::TestObjects::ObjectFactory->tearDownTestContext($subtestContext);
97
98
    $atomicupdate = $atomicUpdater->find({issue_id => 'Bug15'});
99
    ok(not($atomicupdate),
100
       "Bug15-Inserted.pl deleted");
101
    };
102
    if ($@) {
103
        ok(0, $@);
104
    }
105
}
106
107
subtest "List pending atomicupdates" => \&listPendingAtomicupdates;
108
sub listPendingAtomicupdates {
109
    my ($atomicUpdater, $files, $text, $atomicupdates);
110
    my $subtestContext = {};
111
    eval {
112
    ##Test adding update scripts and deploy them, confirm that no pending scripts detected
113
    $files = t::lib::TestObjects::FileFactory->createTestGroup([
114
                        {   filepath => 'atomicupdate/',
115
                            filename => '#911-WhoYouGonnaCall.pl',
116
                            content  => '$ENV{ATOMICUPDATE_TESTS} = 1;',},
117
                        {   filepath => 'atomicupdate/',
118
                            filename => 'Bug911-WhatchaGonnaDo.pl',
119
                            content  => '$ENV{ATOMICUPDATE_TESTS}++;',},
120
                        {   filepath => 'atomicupdate/',
121
                            filename => 'Bug112-LapinlahdenLinnut.pl',
122
                            content  => '$ENV{ATOMICUPDATE_TESTS}++;',},
123
                        ],
124
                        undef, $subtestContext, $testContext);
125
    $atomicUpdater = Koha::AtomicUpdater->new({
126
                            scriptDir => $files->{'#911-WhoYouGonnaCall.pl'}->dirname()
127
                        });
128
129
    $text = $atomicUpdater->listPendingToConsole();
130
    print $text;
131
132
    ok($text =~ m/#911-WhoYouGonnaCall.pl/,
133
       "#911-WhoYouGonnaCall is pending");
134
    ok($text =~ m/Bug911-WhatchaGonnaDo.pl/,
135
       "Bug911-WhatchaGonnaDo is pending");
136
    ok($text =~ m/Bug112-LapinlahdenLinnut.pl/,
137
       'Bug112-LapinlahdenLinnut is pending');
138
139
    $atomicupdates = $atomicUpdater->applyAtomicUpdates();
140
    t::lib::TestObjects::AtomicUpdateFactory->addToContext($atomicupdates, undef, $subtestContext, $testContext); #Keep track of changes
141
142
    is($atomicupdates->{'#911-WhoYouGonnaCall.pl'}->issue_id,
143
       '#911',
144
       "#911-WhoYouGonnaCall.pl deployed");
145
    is($atomicupdates->{'Bug112-LapinlahdenLinnut.pl'}->issue_id,
146
       'Bug112',
147
       'Bug112-LapinlahdenLinnut.pl deployed');
148
    is($atomicupdates->{'Bug911-WhatchaGonnaDo.pl'}->issue_id,
149
       'Bug911',
150
       "Bug911-WhatchaGonnaDo.pl deployed");
151
152
    ##Test adding scripts to the atomicupdates directory and how we deal with such change.
153
    $files = t::lib::TestObjects::FileFactory->createTestGroup([
154
                        {   filepath => 'atomicupdate/',
155
                            filename => '#53-PlaceToBe.pl',
156
                            content  => '$ENV{ATOMICUPDATE_TESTS}++;',},
157
                        {   filepath => 'atomicupdate/',
158
                            filename => '#54-KohaConInFinlandNextYear.pl',
159
                            content  => '$ENV{ATOMICUPDATE_TESTS}++;',},
160
                        {   filepath => 'atomicupdate/',
161
                            filename => '#55-Fiftyfive.pl',
162
                            content  => '$ENV{ATOMICUPDATE_TESTS}++;',},
163
                        ],
164
                        undef, $subtestContext, $testContext);
165
166
    $text = $atomicUpdater->listPendingToConsole();
167
    print $text;
168
169
    ok($text =~ m/#53-PlaceToBe.pl/,
170
       "#53-PlaceToBe.pl is pending");
171
    ok($text =~ m/#54-KohaConInFinlandNextYear.pl/,
172
       "#54-KohaConInFinlandNextYear.pl is pending");
173
    ok($text =~ m/#55-Fiftyfive.pl/u,
174
       '#55-Fiftyfive.pl');
175
176
    $atomicupdates = $atomicUpdater->applyAtomicUpdates();
177
    t::lib::TestObjects::AtomicUpdateFactory->addToContext($atomicupdates, undef, $subtestContext, $testContext); #Keep track of changes
178
179
    is($atomicupdates->{'#53-PlaceToBe.pl'}->issue_id,
180
       '#53',
181
       "#53-PlaceToBe.pl deployed");
182
    is($atomicupdates->{'#54-KohaConInFinlandNextYear.pl'}->issue_id,
183
       '#54',
184
       '#54-KohaConInFinlandNextYear.pl deployed');
185
    is($atomicupdates->{'#55-Fiftyfive.pl'}->issue_id,
186
       '#55',
187
       "#55-Fiftyfive.pl deployed");
188
189
    is($ENV{ATOMICUPDATE_TESTS},
190
       6,
191
       "All configured AtomicUpdates deployed");
192
    };
193
    if ($@) {
194
        ok(0, $@);
195
    }
196
    t::lib::TestObjects::AtomicUpdateFactory->tearDownTestContext($subtestContext);
197
}
198
199
t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext);
200
done_testing;
(-)a/t/lib/TestObjects/AtomicUpdateFactory.pm (+105 lines)
Line 0 Link Here
1
package t::lib::TestObjects::AtomicUpdateFactory;
2
3
# Copyright Vaara-kirjastot 2015
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
#
20
21
use Modern::Perl;
22
use Carp;
23
24
use Koha::AtomicUpdater;
25
use Koha::Database;
26
27
use Koha::Exception::UnknownProgramState;
28
29
use base qw(t::lib::TestObjects::ObjectFactory);
30
31
sub getDefaultHashKey {
32
    return 'issue_id';
33
}
34
sub getObjectType {
35
    return 'Koha::AtomicUpdate';
36
}
37
38
=head t::lib::TestObjects::createTestGroup
39
40
    my $atomicupdates = t::lib::TestObjects::AtomicUpdateFactory->createTestGroup([
41
                            {'issue_id' => 'Bug3432',
42
                             'filename' => 'Bug3432-RavingRabbitsMayhem',
43
                             'modification_time' => '2015-01-02 15:59:32',
44
                            },
45
                        ], undef, $testContext1, $testContext2, $testContext3);
46
47
Calls Koha::AtomicUpdater to add a Koha::AtomicUpdate object to DB.
48
49
The HASH is keyed with the 'koha.atomicupdates.issue_id', or the given $hashKey.
50
51
There is a duplication check to first look for atomicupdate-rows with the same 'issue_id'.
52
If a matching atomicupdate is found, then we use the existing Record instead of adding a new one.
53
54
@RETURNS HASHRef of Koha::AtomicUpdate-objects
55
56
See t::lib::TestObjects::ObjectFactory for more documentation
57
=cut
58
59
sub handleTestObject {
60
    my ($class, $object, $stashes) = @_;
61
62
    ##First see if the given Record already exists in the DB. For testing purposes we use the isbn as the UNIQUE identifier.
63
    my $atomicupdate = Koha::AtomicUpdater->find({issue_id => $object->{issue_id}});
64
    unless ($atomicupdate) {
65
        my $atomicupdater = Koha::AtomicUpdater->new();
66
        $atomicupdate = $atomicupdater->addAtomicUpdate($object);
67
    }
68
69
    Koha::Exception::UnknownProgramState->throw(error => "$class->handleTestObject():> Cannot create a new object\n$@\n")
70
                unless $atomicupdate;
71
72
    return $atomicupdate;
73
}
74
75
=head validateAndPopulateDefaultValues
76
@OVERLOAD
77
78
Validates given Object parameters and makes sure that critical fields are given
79
and populates defaults for missing values.
80
=cut
81
82
sub validateAndPopulateDefaultValues {
83
    my ($self, $object, $hashKey) = @_;
84
85
    $object->{issue_id} = 'BugRancidacid' unless $object->{issue_id};
86
    $object->{filename} = 'BugRancidacid-LaboratoryExperimentsGoneSour' unless $object->{filename};
87
88
    $self->SUPER::validateAndPopulateDefaultValues($object, $hashKey);
89
}
90
91
sub deleteTestGroup {
92
    my ($class, $objects) = @_;
93
94
    while( my ($key, $object) = each %$objects) {
95
        my $atomicupdate = Koha::AtomicUpdater->cast($object);
96
        eval {
97
            $atomicupdate->delete();
98
        };
99
        if ($@) {
100
            warn "$class->deleteTestGroup():> Error hapened: $@\n";
101
        }
102
    }
103
}
104
105
1;
(-)a/t/lib/TestObjects/ObjectFactory.pm (+5 lines)
Lines 166-171 sub tearDownTestContext { Link Here
166
        t::lib::TestObjects::BiblioFactory->deleteTestGroup($stash->{biblio});
166
        t::lib::TestObjects::BiblioFactory->deleteTestGroup($stash->{biblio});
167
        delete $stash->{biblio};
167
        delete $stash->{biblio};
168
    }
168
    }
169
    if ($stash->{atomicupdate}) {
170
        require t::lib::TestObjects::AtomicUpdateFactory;
171
        t::lib::TestObjects::AtomicUpdateFactory->deleteTestGroup($stash->{atomicupdate});
172
        delete $stash->{atomicupdate};
173
    }
169
    if ($stash->{borrower}) {
174
    if ($stash->{borrower}) {
170
        require t::lib::TestObjects::BorrowerFactory;
175
        require t::lib::TestObjects::BorrowerFactory;
171
        t::lib::TestObjects::BorrowerFactory->deleteTestGroup($stash->{borrower});
176
        t::lib::TestObjects::BorrowerFactory->deleteTestGroup($stash->{borrower});
(-)a/t/lib/TestObjects/objectFactories.t (-1 / +39 lines)
Lines 30-35 use t::lib::TestObjects::BorrowerFactory; Link Here
30
use Koha::Borrowers;
30
use Koha::Borrowers;
31
use t::lib::TestObjects::ItemFactory;
31
use t::lib::TestObjects::ItemFactory;
32
use Koha::Items;
32
use Koha::Items;
33
use t::lib::TestObjects::AtomicUpdateFactory;
34
use Koha::AtomicUpdater;
33
use t::lib::TestObjects::BiblioFactory;
35
use t::lib::TestObjects::BiblioFactory;
34
use Koha::Biblios;
36
use Koha::Biblios;
35
use t::lib::TestObjects::CheckoutFactory;
37
use t::lib::TestObjects::CheckoutFactory;
Lines 472-477 sub testLetterTemplateFactory { Link Here
472
474
473
475
474
476
477
########## AtomicUpdateFactory subtests ##########
478
subtest 't::lib::TestObjects::AtomicUpdateFactory' => \&testAtomicUpdateFactory;
479
sub testAtomicUpdateFactory {
480
    my ($atomicUpdater, $atomicupdate);
481
    my $subtestContext = {};
482
    ##Create and Delete using dependencies in the $testContext instantiated in previous subtests.
483
    my $atomicupdates = t::lib::TestObjects::AtomicUpdateFactory->createTestGroup([
484
                            {'issue_id' => 'Bug10',
485
                             'filename' => 'Bug10-RavingRabbitsMayhem',
486
                             'modification_time' => '2015-01-02 15:59:32',},
487
                            {'issue_id' => 'Bug11',
488
                             'filename' => 'Bug11-RancidSausages',
489
                             'modification_time' => '2015-01-02 15:59:33',},
490
                            ],
491
                            undef, $subtestContext);
492
    $atomicUpdater = Koha::AtomicUpdater->new();
493
    $atomicupdate = $atomicUpdater->find({issue_id => $atomicupdates->{Bug10}->issue_id});
494
    is($atomicupdate->issue_id,
495
       'Bug10',
496
       "Bug10-RavingRabbitsMayhem created");
497
    $atomicupdate = $atomicUpdater->find({issue_id => $atomicupdates->{Bug11}->issue_id});
498
    is($atomicupdate->issue_id,
499
       'Bug11',
500
       "Bug11-RancidSausages created");
501
502
    t::lib::TestObjects::ObjectFactory->tearDownTestContext($subtestContext);
503
504
    $atomicupdate = $atomicUpdater->find({issue_id => $atomicupdates->{Bug10}->issue_id});
505
    ok(not($atomicupdate),
506
       "Bug10-RavingRabbitsMayhem deleted");
507
    $atomicupdate = $atomicUpdater->find({issue_id => $atomicupdates->{Bug11}->issue_id});
508
    ok(not($atomicupdate),
509
       "Bug11-RancidSausages created");
510
};
511
512
513
475
########## SystemPreferenceFactory subtests ##########
514
########## SystemPreferenceFactory subtests ##########
476
subtest 't::lib::TestObjects::SystemPreferenceFactory' => \&testSystemPreferenceFactory;
515
subtest 't::lib::TestObjects::SystemPreferenceFactory' => \&testSystemPreferenceFactory;
477
sub testSystemPreferenceFactory {
516
sub testSystemPreferenceFactory {
478
- 

Return to bug 14698