1 package t::lib::TestBuilder;
10 smallint => \&_gen_int,
11 mediumint => \&_gen_int,
12 integer => \&_gen_int,
16 decimal => \&_gen_real,
17 double_precision => \&_gen_real,
19 timestamp => \&_gen_date,
20 datetime => \&_gen_date,
24 varchar => \&_gen_text,
25 tinytext => \&_gen_text,
27 mediumtext => \&_gen_text,
28 longtext => \&_gen_text,
30 set => \&_gen_set_enum,
31 enum => \&_gen_set_enum,
33 tinyblob => \&_gen_blob,
34 mediumblob => \&_gen_blob,
36 longblob => \&_gen_blob,
39 our $default_value = {
42 surname => 'my surname',
43 address => 'my adress',
47 branchname => 'my branchname',
53 default_privacy => 'default',
66 $default_value->{UserPermission}->{code} = $default_value->{UserPermission}->{module_bit};
72 bless( $self, $class );
74 $self->schema( Koha::Database->new()->schema );
76 $self->schema->txn_begin();
78 $self->schema->storage->sql_maker->quote_char('`');
83 my ($self, $schema) = @_;
85 if( defined( $schema ) ) {
86 $self->{schema} = $schema;
88 return $self->{schema};
92 my ($self, $params) = @_;
93 my $source = $self->schema->resultset( $params->{source} );
94 return $source->delete_all();
98 my ($self, $params) = @_;
99 my $source = $params->{source} || return;
100 my $value = $params->{value};
101 my $only_fk = $params->{only_fk} || 0;
103 my $col_values = $self->_buildColumnValues({
109 my $foreign_keys = $self->_getForeignKeys( { source => $source } );
110 for my $fk ( @$foreign_keys ) {
112 my $col_name = $fk->{keys}->[0]->{col_name};
113 if( ref( $col_values->{$col_name} ) eq 'HASH' ) {
114 $fk_value = $col_values->{$col_name};
116 elsif( defined( $col_values->{$col_name} ) ) {
120 my $fk_row = $self->build({
121 source => $fk->{source},
125 my $keys = $fk->{keys};
126 for my $key( @$keys ) {
127 $col_values->{ $key->{col_name} } = $fk_row->{ $key->{col_fk_name} };
128 $data->{ $key->{col_name} } = $fk_row;
134 $new_row = $col_values;
137 $new_row = $self->_storeColumnValues({
139 values => $col_values,
142 $new_row->{_fk} = $data if( defined( $data ) );
148 my $source = $params->{source};
149 $source =~ s|(\w+)$|$1|;
153 sub _buildColumnValues {
154 my ($self, $params) = @_;
155 my $source = _formatSource( { source => $params->{source} } );
156 my $original_value = $params->{value};
159 my @columns = $self->schema->source($source)->columns;
160 my %unique_constraints = $self->schema->source($source)->unique_constraints();
163 BUILD_VALUE: while ( $build_value ) {
164 # generate random values for all columns
165 for my $col_name( @columns ) {
166 my $col_value = $self->_buildColumnValue({
168 column_name => $col_name,
169 value => $original_value,
171 $col_values->{$col_name} = $col_value if( defined( $col_value ) );
175 # If default values are set, maybe the data exist in the DB
176 # But no need to wait for another value
177 # FIXME this can be wrong if a default value is defined for a field
178 # which is not a constraint and that the generated value for the
179 # constraint already exists.
180 last BUILD_VALUE if exists( $default_value->{$source} );
182 # If there is no original value given and unique constraints exist,
183 # check if the generated values do not exist yet.
184 if ( not defined $original_value and scalar keys %unique_constraints > 0 ) {
186 # verify the data would respect each unique constraint
187 CONSTRAINTS: foreach my $constraint (keys %unique_constraints) {
190 my $constraint_columns = $unique_constraints{$constraint};
191 # loop through all constraint columns and build the condition
192 foreach my $constraint_column ( @$constraint_columns ) {
194 $condition->{ $constraint_column } =
195 $col_values->{ $constraint_column };
198 my $count = $self->schema
199 ->resultset( $source )
200 ->search( $condition )
203 # no point checking more stuff, exit the loop
214 # rel_name => $rel_name,
215 # source => $table_name,
217 # col_name => $col_name,
218 # col_fk_name => $col_fk_name,
221 sub _getForeignKeys {
222 my ($self, $params) = @_;
223 my $source = $self->schema->source( $params->{source} );
225 my @foreign_keys = ();
226 my @relationships = $source->relationships;
227 for my $rel_name( @relationships ) {
228 my $rel_info = $source->relationship_info($rel_name);
229 if( $rel_info->{attrs}->{is_foreign_key_constraint} ) {
231 rel_name => $rel_name,
232 source => $rel_info->{source},
236 while( my ($col_fk_name, $col_name) = each(%{$rel_info->{cond}}) ) {
237 $col_name =~ s|self.(\w+)|$1|;
238 $col_fk_name =~ s|foreign.(\w+)|$1|;
240 col_name => $col_name,
241 col_fk_name => $col_fk_name,
244 $rel->{keys} = \@keys;
246 push @foreign_keys, $rel;
249 return \@foreign_keys;
252 sub _storeColumnValues {
253 my ($self, $params) = @_;
254 my $source = $params->{source};
255 my $col_values = $params->{values};
259 $new_row = $self->schema->resultset($source)->update_or_create($col_values);
261 die "$source - $@\n" if ($@);
264 $new_row = { $new_row->get_columns };
266 warn "$source - $@\n" if ($@);
270 sub _buildColumnValue {
271 my ($self, $params) = @_;
272 my $source = $params->{source};
273 my $value = $params->{value};
274 my $col_name = $params->{column_name};
275 my $col_info = $self->schema->source($source)->column_info($col_name);
278 if( exists( $value->{$col_name} ) ) {
279 $col_value = $value->{$col_name};
281 elsif( exists $default_value->{$source} and exists $default_value->{$source}->{$col_name} ) {
282 $col_value = $default_value->{$source}->{$col_name};
284 elsif( not $col_info->{default_value} and not $col_info->{is_auto_increment} and not $col_info->{is_foreign_key} ) {
286 my $data_type = $col_info->{data_type};
287 $data_type =~ s| |_|;
288 $col_value = $gen_type->{$data_type}->( $self, { info => $col_info } );
290 die "The type $col_info->{data_type} is not defined\n" if ($@);
297 my ($self, $params) = @_;
298 my $data_type = $params->{info}->{data_type};
301 if( $data_type eq 'tinyint' ) {
304 elsif( $data_type eq 'smallint' ) {
307 elsif( $data_type eq 'mediumint' ) {
310 elsif( $data_type eq 'integer' ) {
313 elsif( $data_type eq 'bigint' ) {
314 $max = 9223372036854775807;
316 return int( rand($max+1) );
320 my ($self, $params) = @_;
322 if( defined( $params->{info}->{size} ) ) {
323 $max = 10 ** ($params->{info}->{size}->[0] - $params->{info}->{size}->[1]);
325 return rand($max) + 1;
329 my ($self, $params) = @_;
330 return $self->schema->storage->datetime_parser->format_datetime(DateTime->now());
334 my ($self, $params) = @_;
335 # From perldoc String::Random
336 # max: specify the maximum number of characters to return for * and other
337 # regular expression patters that don't return a fixed number of characters
338 my $regex = '[A-Za-z][A-Za-z0-9_]*';
339 my $size = $params->{info}{size};
340 if ( defined $size and $size > 1 ) {
342 } elsif ( defined $size and $size == 1 ) {
345 my $random = String::Random->new( max => $size );
346 return $random->randregex($regex);
350 my ($self, $params) = @_;
351 return $params->{info}->{extra}->{list}->[0];
355 my ($self, $params) = @_;;
363 $self->schema->txn_rollback();
370 t::lib::TestBuilder.pm - Koha module to simplify the writing of tests
374 use t::lib::TestBuilder;
376 Koha module to insert the foreign keys automatically for the tests
380 This module allows to insert automatically an entry in the database. All the database changes are wrapped in a transaction.
381 The foreign keys are created according to the DBIx::Class schema.
382 The taken values are the values by default if it is possible or randomly generated.
388 $builder = t::lib::TestBuilder->new()
390 Constructor - Begins a transaction and returns the object TestBuilder
394 $schema = $builder->schema
396 Getter - Returns the schema of DBIx::Class
400 $builder->clear({ source => $source_name })
404 =item C<$source_name> is the name of the source in the DBIx::Class schema (required)
408 Clears all the data of this source (database table)
413 source => $source_name,
420 =item C<$source_name> is the name of the source in the DBIx::Class schema (required)
422 =item C<$value> is the values for the entry (optional)
424 =item C<$only_fk> is a boolean to indicate if only the foreign keys are created (optional)
428 Inserts an entry in the database by instanciating all the foreign keys.
429 The values can be specified, the values which are not given are default values if they exists or generated randomly.
430 Returns the values of the entry as a hashref with an extra key : _fk which contains all the values of the generated foreign keys.
434 Yohann Dufour <yohann.dufour@biblibre.com>
438 Copyright 2014 - Biblibre SARL
442 This file is part of Koha.
444 Koha is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
445 the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
447 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.
449 You should have received a copy of the GNU General Public License along with Koha; if not, see <http://www.gnu.org/licenses>.