mysql test was broken for mysqlds that do not support innodb at all, fixed now
[dbsrgits/DBIx-Class-Schema-Loader.git] / t / dbixcsl_common_tests.pm
1 package dbixcsl_common_tests;
2
3 use strict;
4 use warnings;
5
6 use Test::More;
7 use DBIx::Class::Schema::Loader;
8 use DBI;
9
10 sub new {
11     my $class = shift;
12
13     my $self;
14
15     if( ref($_[0]) eq 'HASH') {
16        my $args = shift;
17        $self = { (%$args) };
18     }
19     else {
20        $self = { @_ };
21     }
22
23     # Only MySQL uses this
24     $self->{innodb} ||= '';
25     
26     $self->{verbose} = $ENV{TEST_VERBOSE} || 0;
27
28     return bless $self => $class;
29 }
30
31 sub skip_tests {
32     my ($self, $why) = @_;
33
34     plan skip_all => $why;
35 }
36
37 sub run_tests {
38     my $self = shift;
39
40     plan tests => 38;
41
42     $self->create();
43
44     my $schema_class = 'DBIXCSL_Test_' . $self->{vendor} . '::Schema';
45
46     my $debug = ($self->{verbose} > 1) ? 1 : 0;
47
48     my %loader_opts = (
49         dsn                     => $self->{dsn},
50         user                    => $self->{user},
51         password                => $self->{password},
52         constraint              => '^(?:\S+\.)?(?i:loader_test)[0-9]+$',
53         relationships           => 1,
54         additional_classes      => 'TestAdditional',
55         additional_base_classes => 'TestAdditionalBase',
56         left_base_classes       => [ qw/TestLeftBase/ ],
57         debug                   => $debug,
58     );
59
60     $loader_opts{db_schema} = $self->{db_schema} if $self->{db_schema};
61     $loader_opts{drop_db_schema} = $self->{drop_db_schema} if $self->{drop_db_schema};
62
63     eval qq{
64         package $schema_class;
65         use base qw/DBIx::Class::Schema::Loader/;
66
67         __PACKAGE__->load_from_connection(\%loader_opts);
68     };
69     ok(!$@, "Loader initialization") or diag $@;
70
71     my $conn = $schema_class->connect($self->{dsn},$self->{user},$self->{password});
72     my $monikers = $schema_class->loader->monikers;
73     my $classes = $schema_class->loader->classes;
74
75     my $moniker1 = $monikers->{loader_test1};
76     my $class1   = $classes->{loader_test1};
77     my $rsobj1   = $conn->resultset($moniker1);
78
79     my $moniker2 = $monikers->{loader_test2};
80     my $class2   = $classes->{loader_test2};
81     my $rsobj2   = $conn->resultset($moniker2);
82
83     isa_ok( $rsobj1, "DBIx::Class::ResultSet" );
84     isa_ok( $rsobj2, "DBIx::Class::ResultSet" );
85
86     can_ok( $class1, 'test_additional_base' );
87     can_ok( $class1, 'test_additional_base_override' );
88     can_ok( $class1, 'test_additional_base_additional' );
89
90     is( $class1->test_additional_base, "test_additional_base",
91         "Additional Base method" );
92
93     is( $class1->test_additional_base_override, "test_left_base_override",
94         "Left Base overrides Additional Base method" );
95
96     is( $class1->test_additional_base_additional, "test_additional",
97         "Additional Base can use Additional package method" );
98
99     my $obj    = $rsobj1->find(1);
100     is( $obj->id,  1 );
101     is( $obj->dat, "foo" );
102     is( $rsobj2->count, 4 );
103
104     my ($obj2) = $rsobj2->find( dat => 'bbb' );
105     is( $obj2->id, 2 );
106
107     SKIP: {
108         skip $self->{skip_rels}, 25 if $self->{skip_rels};
109
110         my $moniker3 = $monikers->{loader_test3};
111         my $class3   = $classes->{loader_test3};
112         my $rsobj3   = $conn->resultset($moniker3);
113
114         my $moniker4 = $monikers->{loader_test4};
115         my $class4   = $classes->{loader_test4};
116         my $rsobj4   = $conn->resultset($moniker4);
117
118         my $moniker5 = $monikers->{loader_test5};
119         my $class5   = $classes->{loader_test5};
120         my $rsobj5   = $conn->resultset($moniker5);
121
122         my $moniker6 = $monikers->{loader_test6};
123         my $class6   = $classes->{loader_test6};
124         my $rsobj6   = $conn->resultset($moniker6);
125
126         my $moniker7 = $monikers->{loader_test7};
127         my $class7   = $classes->{loader_test7};
128         my $rsobj7   = $conn->resultset($moniker7);
129
130         my $moniker8 = $monikers->{loader_test8};
131         my $class8   = $classes->{loader_test8};
132         my $rsobj8   = $conn->resultset($moniker8);
133
134         my $moniker9 = $monikers->{loader_test9};
135         my $class9   = $classes->{loader_test9};
136         my $rsobj9   = $conn->resultset($moniker9);
137
138         isa_ok( $rsobj3, "DBIx::Class::ResultSet" );
139         isa_ok( $rsobj4, "DBIx::Class::ResultSet" );
140         isa_ok( $rsobj5, "DBIx::Class::ResultSet" );
141         isa_ok( $rsobj6, "DBIx::Class::ResultSet" );
142         isa_ok( $rsobj7, "DBIx::Class::ResultSet" );
143         isa_ok( $rsobj8, "DBIx::Class::ResultSet" );
144         isa_ok( $rsobj9, "DBIx::Class::ResultSet" );
145
146         # basic rel test
147         my $obj4 = $rsobj4->find(123);
148         isa_ok( $obj4->fkid, $class3);
149
150         # fk def in comments should not be parsed
151         my $obj5 = $rsobj5->find( id1 => 1, id2 => 1 );
152         is( ref( $obj5->id2 ), '' );
153
154         # mulit-col fk def
155         my $obj6 = $rsobj6->find(1);
156         isa_ok( $obj6->loader_test2, $class2);
157         isa_ok( $obj6->loader_test5, $class5);
158
159         # fk that references a non-pk key (UNIQUE)
160         my $obj8 = $rsobj8->find(1);
161         isa_ok( $obj8->loader_test7, $class7);
162
163         # from Chisel's tests...
164         SKIP: {
165             if($self->{vendor} =~ /sqlite/i) {
166                 skip 'SQLite cannot do the advanced tests', 8;
167             }
168
169             my $moniker10 = $monikers->{loader_test10};
170             my $class10   = $classes->{loader_test10};
171             my $rsobj10   = $conn->resultset($moniker10);
172
173             my $moniker11 = $monikers->{loader_test11};
174             my $class11   = $classes->{loader_test11};
175             my $rsobj11   = $conn->resultset($moniker11);
176
177             isa_ok( $rsobj10, "DBIx::Class::ResultSet" ); 
178             isa_ok( $rsobj11, "DBIx::Class::ResultSet" );
179
180             my $obj10 = $rsobj10->create({ subject => 'xyzzy' });
181
182             $obj10->update();
183             ok( defined $obj10, '$obj10 is defined' );
184
185             my $obj11 = $rsobj11->create({ loader_test10 => $obj10->id() });
186             $obj11->update();
187             ok( defined $obj11, '$obj11 is defined' );
188
189             eval {
190                 my $obj10_2 = $obj11->loader_test10;
191                 $obj10_2->loader_test11( $obj11->id11() );
192                 $obj10_2->update();
193             };
194             is($@, '', 'No errors after eval{}');
195
196             SKIP: {
197                 skip 'Previous eval block failed', 3
198                     unless ($@ eq '');
199         
200                 my $results = $rsobj10->search({ subject => 'xyzzy' });
201                 is( $results->count(), 1,
202                     'One $rsobj10 returned from search' );
203
204                 my $obj10_3 = $results->first();
205                 isa_ok( $obj10_3, $class10 );
206                 is( $obj10_3->loader_test11()->id(), $obj11->id(),
207                     'found same $rsobj11 object we expected' );
208             }
209         }
210
211         SKIP: {
212             skip 'This vendor cannot do inline relationship definitions', 5
213                 if $self->{no_inline_rels};
214
215             my $moniker12 = $monikers->{loader_test12};
216             my $class12   = $classes->{loader_test12};
217             my $rsobj12   = $conn->resultset($moniker12);
218
219             my $moniker13 = $monikers->{loader_test13};
220             my $class13   = $classes->{loader_test13};
221             my $rsobj13   = $conn->resultset($moniker13);
222
223             isa_ok( $rsobj12, "DBIx::Class::ResultSet" ); 
224             isa_ok( $rsobj13, "DBIx::Class::ResultSet" );
225
226             my $obj13 = $rsobj13->find(1);
227             isa_ok( $obj13->id, $class12 );
228             isa_ok( $obj13->loader_test12, $class12);
229             isa_ok( $obj13->dat, $class12);
230         }
231     }
232 }
233
234 sub dbconnect {
235     my ($self, $complain) = @_;
236
237     my $dbh = DBI->connect(
238          $self->{dsn}, $self->{user},
239          $self->{password},
240          {
241              RaiseError => $complain,
242              PrintError => $complain,
243              AutoCommit => 1,
244          }
245     );
246
247     die "Failed to connect to database: $DBI::errstr" if !$dbh;
248
249     return $dbh;
250 }
251
252 sub create {
253     my $self = shift;
254
255     my @statements = (
256         qq{
257             CREATE TABLE loader_test1 (
258                 id $self->{auto_inc_pk},
259                 dat VARCHAR(32)
260             ) $self->{innodb}
261         },
262
263         q{ INSERT INTO loader_test1 (dat) VALUES('foo') },
264         q{ INSERT INTO loader_test1 (dat) VALUES('bar') }, 
265         q{ INSERT INTO loader_test1 (dat) VALUES('baz') }, 
266
267         qq{ 
268             CREATE TABLE loader_test2 (
269                 id $self->{auto_inc_pk},
270                 dat VARCHAR(32)
271             ) $self->{innodb}
272         },
273
274         q{ INSERT INTO loader_test2 (dat) VALUES('aaa') }, 
275         q{ INSERT INTO loader_test2 (dat) VALUES('bbb') }, 
276         q{ INSERT INTO loader_test2 (dat) VALUES('ccc') }, 
277         q{ INSERT INTO loader_test2 (dat) VALUES('ddd') }, 
278     );
279
280     my @statements_reltests = (
281         qq{
282             CREATE TABLE loader_test3 (
283                 id INTEGER NOT NULL PRIMARY KEY,
284                 dat VARCHAR(32)
285             ) $self->{innodb}
286         },
287
288         q{ INSERT INTO loader_test3 (id,dat) VALUES(1,'aaa') }, 
289         q{ INSERT INTO loader_test3 (id,dat) VALUES(2,'bbb') }, 
290         q{ INSERT INTO loader_test3 (id,dat) VALUES(3,'ccc') }, 
291         q{ INSERT INTO loader_test3 (id,dat) VALUES(4,'ddd') }, 
292
293         qq{
294             CREATE TABLE loader_test4 (
295                 id INTEGER NOT NULL PRIMARY KEY,
296                 fkid INTEGER NOT NULL,
297                 dat VARCHAR(32),
298                 FOREIGN KEY (fkid) REFERENCES loader_test3 (id)
299             ) $self->{innodb}
300         },
301
302         q{ INSERT INTO loader_test4 (id,fkid,dat) VALUES(123,1,'aaa') },
303         q{ INSERT INTO loader_test4 (id,fkid,dat) VALUES(124,2,'bbb') }, 
304         q{ INSERT INTO loader_test4 (id,fkid,dat) VALUES(125,3,'ccc') },
305         q{ INSERT INTO loader_test4 (id,fkid,dat) VALUES(126,4,'ddd') },
306
307         qq{
308             CREATE TABLE loader_test5 (
309                 id1 INTEGER NOT NULL,
310                 id2 INTEGER NOT NULL, -- , id2 INTEGER REFERENCES loader_test1,
311                 dat VARCHAR(8),
312                 PRIMARY KEY (id1,id2)
313             ) $self->{innodb}
314         },
315
316         q{ INSERT INTO loader_test5 (id1,id2,dat) VALUES (1,1,'aaa') },
317
318         qq{
319             CREATE TABLE loader_test6 (
320                 id INTEGER NOT NULL PRIMARY KEY,
321                 id2 INTEGER,
322                 loader_test2 INTEGER,
323                 dat VARCHAR(8),
324                 FOREIGN KEY (loader_test2) REFERENCES loader_test2 (id),
325                 FOREIGN KEY (id, id2 ) REFERENCES loader_test5 (id1,id2)
326             ) $self->{innodb}
327         },
328
329         (q{ INSERT INTO loader_test6 (id, id2,loader_test2,dat) } .
330          q{ VALUES (1, 1,1,'aaa') }),
331
332         qq{
333             CREATE TABLE loader_test7 (
334                 id INTEGER NOT NULL PRIMARY KEY,
335                 id2 VARCHAR(8) NOT NULL UNIQUE,
336                 dat VARCHAR(8)
337             ) $self->{innodb}
338         },
339
340         q{ INSERT INTO loader_test7 (id,id2,dat) VALUES (1,'aaa','bbb') },
341
342         qq{
343             CREATE TABLE loader_test8 (
344                 id INTEGER NOT NULL PRIMARY KEY,
345                 loader_test7 VARCHAR(8) NOT NULL,
346                 dat VARCHAR(8),
347                 FOREIGN KEY (loader_test7) REFERENCES loader_test7 (id2)
348             ) $self->{innodb}
349         },
350
351         (q{ INSERT INTO loader_test8 (id,loader_test7,dat) } .
352          q{ VALUES (1,'aaa','bbb') }),
353
354         qq{
355             CREATE TABLE loader_test9 (
356                 loader_test9 VARCHAR(8) NOT NULL
357             ) $self->{innodb}
358         },
359     );
360
361     my @statements_advanced = (
362         qq{
363             CREATE TABLE loader_test10 (
364                 id10 $self->{auto_inc_pk},
365                 subject VARCHAR(8),
366                 loader_test11 INTEGER
367             ) $self->{innodb}
368         },
369
370         qq{
371             CREATE TABLE loader_test11 (
372                 id11 $self->{auto_inc_pk},
373                 message VARCHAR(8) DEFAULT 'foo',
374                 loader_test10 INTEGER,
375                 FOREIGN KEY (loader_test10) REFERENCES loader_test10 (id10)
376             ) $self->{innodb}
377         },
378
379         (q{ ALTER TABLE loader_test10 ADD CONSTRAINT } .
380          q{ loader_test11_fk FOREIGN KEY (loader_test11) } .
381          q{ REFERENCES loader_test11 (id11) }),
382     );
383
384     my @statements_inline_rels = (
385         qq{
386             CREATE TABLE loader_test12 (
387                 id INTEGER NOT NULL PRIMARY KEY,
388                 id2 VARCHAR(8) NOT NULL UNIQUE,
389                 dat VARCHAR(8) NOT NULL UNIQUE
390             ) $self->{innodb}
391         },
392
393         q{ INSERT INTO loader_test12 (id,id2,dat) VALUES (1,'aaa','bbb') },
394
395         qq{
396             CREATE TABLE loader_test13 (
397                 id INTEGER NOT NULL PRIMARY KEY REFERENCES loader_test12,
398                 loader_test12 VARCHAR(8) NOT NULL REFERENCES loader_test12 (id2),
399                 dat VARCHAR(8) REFERENCES loader_test12 (dat)
400             ) $self->{innodb}
401         },
402
403         (q{ INSERT INTO loader_test13 (id,loader_test12,dat) } .
404          q{ VALUES (1,'aaa','bbb') }),
405     );
406
407
408     $self->drop_tables;
409
410     $self->{created} = 1;
411
412     my $dbh = $self->dbconnect(1);
413     $dbh->do($_) for (@statements);
414     unless($self->{skip_rels}) {
415         # hack for now, since DB2 doesn't like inline comments, and we need
416         # to test one for mysql, which works on everyone else...
417         # this all needs to be refactored anyways.
418         if($self->{vendor} =~ /DB2/i) {
419             @statements_reltests = map { s/--.*\n//; $_ } @statements_reltests;
420         }
421         $dbh->do($_) for (@statements_reltests);
422         unless($self->{vendor} =~ /sqlite/i) {
423             $dbh->do($_) for (@statements_advanced);
424         }
425         unless($self->{no_inline_rels}) {
426             $dbh->do($_) for (@statements_inline_rels);
427         }
428     }
429     $dbh->disconnect();
430 }
431
432 sub drop_tables {
433     my $self = shift;
434
435     return unless $self->{created};
436
437     my @tables = qw/
438         loader_test1
439         loader_test2
440     /;
441
442     my @tables_reltests = qw/
443         loader_test4
444         loader_test3
445         loader_test6
446         loader_test5
447         loader_test8
448         loader_test7
449         loader_test9
450     /;
451
452     my @tables_advanced = qw/
453         loader_test11
454         loader_test10
455     /;
456
457     my @tables_inline_rels = qw/
458         loader_test13
459         loader_test12
460     /;
461
462     my $drop_fk_mysql =
463         q{ALTER TABLE loader_test10 DROP FOREIGN KEY loader_test11_fk;};
464
465     my $drop_fk =
466         q{ALTER TABLE loader_test10 DROP CONSTRAINT loader_test11_fk;};
467
468     my $dbh = $self->dbconnect(0);
469
470     unless($self->{skip_rels}) {
471         $dbh->do("DROP TABLE $_") for (@tables_reltests);
472         unless($self->{vendor} =~ /sqlite/i) {
473             if($self->{vendor} =~ /mysql/i) {
474                 $dbh->do($drop_fk_mysql);
475             }
476             else {
477                 $dbh->do($drop_fk);
478             }
479             $dbh->do("DROP TABLE $_") for (@tables_advanced);
480         }
481         unless($self->{no_inline_rels}) {
482             $dbh->do("DROP TABLE $_") for (@tables_inline_rels);
483         }
484     }
485     $dbh->do("DROP TABLE $_") for (@tables);
486     $dbh->disconnect;
487 }
488
489 sub DESTROY { shift->drop_tables; }
490
491 1;