Commit | Line | Data |
70350518 |
1 | use strict; |
2 | use warnings; |
3 | |
4 | use Test::More; |
5 | use lib qw(t/lib); |
6 | use DBICTest; |
7 | |
a47e1233 |
8 | my $schema = DBICTest->init_schema(); |
70350518 |
9 | |
57c18b65 |
10 | plan tests => 54; |
a62cf8d4 |
11 | |
12 | my $code = sub { |
13 | my ($artist, @cd_titles) = @_; |
14 | |
15 | $artist->create_related('cds', { |
16 | title => $_, |
17 | year => 2006, |
18 | }) foreach (@cd_titles); |
19 | |
20 | return $artist->cds->all; |
21 | }; |
22 | |
171dadd7 |
23 | # Test checking of parameters |
24 | { |
171dadd7 |
25 | eval { |
26 | (ref $schema)->txn_do(sub{}); |
27 | }; |
f32eb113 |
28 | like($@, qr/storage/, "can't call txn_do without storage"); |
171dadd7 |
29 | eval { |
30 | $schema->txn_do(''); |
31 | }; |
32 | like($@, qr/must be a CODE reference/, '$coderef parameter check ok'); |
33 | } |
34 | |
a62cf8d4 |
35 | # Test successful txn_do() - scalar context |
36 | { |
57c18b65 |
37 | is( $schema->storage->{transaction_depth}, 0, 'txn depth starts at 0'); |
38 | |
a62cf8d4 |
39 | my @titles = map {'txn_do test CD ' . $_} (1..5); |
40 | my $artist = $schema->resultset('Artist')->find(1); |
41 | my $count_before = $artist->cds->count; |
42 | my $count_after = $schema->txn_do($code, $artist, @titles); |
43 | is($count_after, $count_before+5, 'successful txn added 5 cds'); |
44 | is($artist->cds({ |
45 | title => "txn_do test CD $_", |
46 | })->first->year, 2006, "new CD $_ year correct") for (1..5); |
57c18b65 |
47 | |
48 | is( $schema->storage->{transaction_depth}, 0, 'txn depth has been reset'); |
a62cf8d4 |
49 | } |
50 | |
51 | # Test successful txn_do() - list context |
52 | { |
57c18b65 |
53 | is( $schema->storage->{transaction_depth}, 0, 'txn depth starts at 0'); |
54 | |
a62cf8d4 |
55 | my @titles = map {'txn_do test CD ' . $_} (6..10); |
56 | my $artist = $schema->resultset('Artist')->find(1); |
57 | my $count_before = $artist->cds->count; |
58 | my @cds = $schema->txn_do($code, $artist, @titles); |
59 | is(scalar @cds, $count_before+5, 'added 5 CDs and returned in list context'); |
60 | is($artist->cds({ |
61 | title => "txn_do test CD $_", |
62 | })->first->year, 2006, "new CD $_ year correct") for (6..10); |
57c18b65 |
63 | |
64 | is( $schema->storage->{transaction_depth}, 0, 'txn depth has been reset'); |
a62cf8d4 |
65 | } |
66 | |
67 | # Test nested successful txn_do() |
68 | { |
57c18b65 |
69 | is( $schema->storage->{transaction_depth}, 0, 'txn depth starts at 0'); |
70 | |
a62cf8d4 |
71 | my $nested_code = sub { |
72 | my ($schema, $artist, $code) = @_; |
73 | |
74 | my @titles1 = map {'nested txn_do test CD ' . $_} (1..5); |
75 | my @titles2 = map {'nested txn_do test CD ' . $_} (6..10); |
76 | |
77 | $schema->txn_do($code, $artist, @titles1); |
78 | $schema->txn_do($code, $artist, @titles2); |
79 | }; |
80 | |
81 | my $artist = $schema->resultset('Artist')->find(2); |
82 | my $count_before = $artist->cds->count; |
83 | |
84 | eval { |
85 | $schema->txn_do($nested_code, $schema, $artist, $code); |
86 | }; |
87 | |
88 | my $error = $@; |
89 | |
90 | ok(!$error, 'nested txn_do succeeded'); |
91 | is($artist->cds({ |
92 | title => 'nested txn_do test CD '.$_, |
93 | })->first->year, 2006, qq{nested txn_do CD$_ year ok}) for (1..10); |
94 | is($artist->cds->count, $count_before+10, 'nested txn_do added all CDs'); |
57c18b65 |
95 | |
96 | is( $schema->storage->{transaction_depth}, 0, 'txn depth has been reset'); |
a62cf8d4 |
97 | } |
98 | |
99 | my $fail_code = sub { |
100 | my ($artist) = @_; |
101 | $artist->create_related('cds', { |
102 | title => 'this should not exist', |
103 | year => 2005, |
104 | }); |
105 | die "the sky is falling"; |
106 | }; |
107 | |
108 | # Test failed txn_do() |
109 | { |
57c18b65 |
110 | |
111 | is( $schema->storage->{transaction_depth}, 0, 'txn depth starts at 0'); |
112 | |
113 | my $artist = $schema->resultset('Artist')->find(3); |
114 | |
115 | eval { |
116 | $schema->txn_do($fail_code, $artist); |
117 | }; |
118 | |
119 | my $error = $@; |
120 | |
121 | like($error, qr/the sky is falling/, 'failed txn_do threw an exception'); |
122 | my $cd = $artist->cds({ |
123 | title => 'this should not exist', |
124 | year => 2005, |
125 | })->first; |
126 | ok(!defined($cd), q{failed txn_do didn't change the cds table}); |
127 | |
128 | is( $schema->storage->{transaction_depth}, 0, 'txn depth has been reset'); |
129 | } |
130 | |
131 | # do the same transaction again |
132 | { |
133 | is( $schema->storage->{transaction_depth}, 0, 'txn depth starts at 0'); |
134 | |
a62cf8d4 |
135 | my $artist = $schema->resultset('Artist')->find(3); |
136 | |
137 | eval { |
138 | $schema->txn_do($fail_code, $artist); |
139 | }; |
140 | |
141 | my $error = $@; |
142 | |
143 | like($error, qr/the sky is falling/, 'failed txn_do threw an exception'); |
144 | my $cd = $artist->cds({ |
145 | title => 'this should not exist', |
146 | year => 2005, |
147 | })->first; |
148 | ok(!defined($cd), q{failed txn_do didn't change the cds table}); |
57c18b65 |
149 | |
150 | is( $schema->storage->{transaction_depth}, 0, 'txn depth has been reset'); |
a62cf8d4 |
151 | } |
152 | |
153 | # Test failed txn_do() with failed rollback |
154 | { |
57c18b65 |
155 | is( $schema->storage->{transaction_depth}, 0, 'txn depth starts at 0'); |
156 | |
a62cf8d4 |
157 | my $artist = $schema->resultset('Artist')->find(3); |
158 | |
159 | # Force txn_rollback() to throw an exception |
160 | no warnings 'redefine'; |
58d387fe |
161 | no strict 'refs'; |
57c18b65 |
162 | |
163 | # die in rollback, but maintain sanity for further tests ... |
164 | local *{"DBIx::Class::Storage::DBI::SQLite::txn_rollback"} = sub{ |
165 | my $storage = shift; |
166 | $storage->{transaction_depth}--; |
167 | die 'FAILED'; |
168 | }; |
a62cf8d4 |
169 | |
170 | eval { |
171 | $schema->txn_do($fail_code, $artist); |
172 | }; |
173 | |
174 | my $error = $@; |
175 | |
176 | like($error, qr/Rollback failed/, 'failed txn_do with a failed '. |
177 | 'txn_rollback threw a rollback exception'); |
178 | like($error, qr/the sky is falling/, 'failed txn_do with a failed '. |
179 | 'txn_rollback included the original exception'); |
180 | |
181 | my $cd = $artist->cds({ |
182 | title => 'this should not exist', |
183 | year => 2005, |
184 | })->first; |
185 | isa_ok($cd, 'DBICTest::CD', q{failed txn_do with a failed txn_rollback }. |
186 | q{changed the cds table}); |
187 | $cd->delete; # Rollback failed |
188 | $cd = $artist->cds({ |
189 | title => 'this should not exist', |
190 | year => 2005, |
191 | })->first; |
192 | ok(!defined($cd), q{deleted the failed txn's cd}); |
57c18b65 |
193 | $schema->storage->_dbh->rollback; |
a62cf8d4 |
194 | } |
195 | |
196 | # Test nested failed txn_do() |
197 | { |
57c18b65 |
198 | is( $schema->storage->{transaction_depth}, 0, 'txn depth starts at 0'); |
199 | |
a62cf8d4 |
200 | my $nested_fail_code = sub { |
201 | my ($schema, $artist, $code1, $code2) = @_; |
202 | |
203 | my @titles = map {'nested txn_do test CD ' . $_} (1..5); |
204 | |
205 | $schema->txn_do($code1, $artist, @titles); # successful txn |
206 | $schema->txn_do($code2, $artist); # failed txn |
207 | }; |
208 | |
209 | my $artist = $schema->resultset('Artist')->find(3); |
210 | |
211 | eval { |
212 | $schema->txn_do($nested_fail_code, $schema, $artist, $code, $fail_code); |
213 | }; |
214 | |
215 | my $error = $@; |
216 | |
217 | like($error, qr/the sky is falling/, 'nested failed txn_do threw exception'); |
218 | ok(!defined($artist->cds({ |
219 | title => 'nested txn_do test CD '.$_, |
220 | year => 2006, |
221 | })->first), qq{failed txn_do didn't add first txn's cd $_}) for (1..5); |
222 | my $cd = $artist->cds({ |
223 | title => 'this should not exist', |
224 | year => 2005, |
225 | })->first; |
226 | ok(!defined($cd), q{failed txn_do didn't add failed txn's cd}); |
227 | } |
a62cf8d4 |
228 | |
291bf95f |
229 | # Grab a new schema to test txn before connect |
230 | { |
231 | my $schema2 = DBICTest->init_schema(no_deploy => 1); |
232 | eval { |
233 | $schema2->txn_begin(); |
234 | $schema2->txn_begin(); |
235 | }; |
236 | my $err = $@; |
237 | ok(($err eq ''), 'Pre-connection nested transactions.'); |
238 | } |