Skip error/warn frames within CAG - saner callsite error messages this way
[dbsrgits/DBIx-Class.git] / t / 98savepoints.t
1 use strict;
2 use warnings;
3
4 use Test::More;
5 use DBIx::Class::Optional::Dependencies ();
6
7 my ($create_sql, $dsn, $user, $pass);
8
9 if ($ENV{DBICTEST_PG_DSN}) {
10   plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('rdbms_pg')
11     unless DBIx::Class::Optional::Dependencies->req_ok_for ('rdbms_pg');
12
13   ($dsn, $user, $pass) = @ENV{map { "DBICTEST_PG_${_}" } qw/DSN USER PASS/};
14
15   $create_sql = "CREATE TABLE artist (artistid serial PRIMARY KEY, name VARCHAR(100), rank INTEGER NOT NULL DEFAULT '13', charfield CHAR(10))";
16 } elsif ($ENV{DBICTEST_MYSQL_DSN}) {
17   plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_mysql')
18     unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_mysql');
19
20   ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MYSQL_${_}" } qw/DSN USER PASS/};
21
22   $create_sql = "CREATE TABLE artist (artistid INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), rank INTEGER NOT NULL DEFAULT '13', charfield CHAR(10)) ENGINE=InnoDB";
23 } else {
24   plan skip_all => 'Set DBICTEST_(PG|MYSQL)_DSN _USER and _PASS if you want to run savepoint tests';
25 }
26
27 use lib qw(t/lib);
28 use DBICTest;
29 use DBICTest::Stats;
30
31 plan tests => 16;
32
33 my $schema = DBICTest::Schema->connect ($dsn,$user,$pass,{ auto_savepoint => 1 });
34
35 my $stats = DBICTest::Stats->new;
36
37 $schema->storage->debugobj($stats);
38
39 $schema->storage->debug(1);
40
41 {
42     local $SIG{__WARN__} = sub {};
43     $schema->storage->dbh->do ('DROP TABLE IF EXISTS artist');
44     $schema->storage->dbh->do ($create_sql);
45 }
46
47 $schema->resultset('Artist')->create({ name => 'foo' });
48
49 $schema->txn_begin;
50
51 my $arty = $schema->resultset('Artist')->find(1);
52
53 my $name = $arty->name;
54
55 # First off, test a generated savepoint name
56 $schema->svp_begin;
57
58 cmp_ok($stats->{'SVP_BEGIN'}, '==', 1, 'Statistics svp_begin tickled');
59
60 $arty->update({ name => 'Jheephizzy' });
61
62 $arty->discard_changes;
63
64 cmp_ok($arty->name, 'eq', 'Jheephizzy', 'Name changed');
65
66 # Rollback the generated name
67 # Active: 0
68 $schema->svp_rollback;
69
70 cmp_ok($stats->{'SVP_ROLLBACK'}, '==', 1, 'Statistics svp_rollback tickled');
71
72 $arty->discard_changes;
73
74 cmp_ok($arty->name, 'eq', $name, 'Name rolled back');
75
76 $arty->update({ name => 'Jheephizzy'});
77
78 # Active: 0 1
79 $schema->svp_begin('testing1');
80
81 $arty->update({ name => 'yourmom' });
82
83 # Active: 0 1 2
84 $schema->svp_begin('testing2');
85
86 $arty->update({ name => 'gphat' });
87 $arty->discard_changes;
88 cmp_ok($arty->name, 'eq', 'gphat', 'name changed');
89 # Active: 0 1 2
90 # Rollback doesn't DESTROY the savepoint, it just rolls back to the value
91 # at it's conception
92 $schema->svp_rollback('testing2');
93 $arty->discard_changes;
94 cmp_ok($arty->name, 'eq', 'yourmom', 'testing2 reverted');
95
96 # Active: 0 1 2 3
97 $schema->svp_begin('testing3');
98 $arty->update({ name => 'coryg' });
99 # Active: 0 1 2 3 4
100 $schema->svp_begin('testing4');
101 $arty->update({ name => 'watson' });
102
103 # Release 3, which implicitly releases 4
104 # Active: 0 1 2
105 $schema->svp_release('testing3');
106 $arty->discard_changes;
107 cmp_ok($arty->name, 'eq', 'watson', 'release left data');
108 # This rolls back savepoint 2
109 # Active: 0 1 2
110 $schema->svp_rollback;
111 $arty->discard_changes;
112 cmp_ok($arty->name, 'eq', 'yourmom', 'rolled back to 2');
113
114 # Rollback the original savepoint, taking us back to the beginning, implicitly
115 # rolling back savepoint 1 and 2
116 $schema->svp_rollback('savepoint_0');
117 $arty->discard_changes;
118 cmp_ok($arty->name, 'eq', 'foo', 'rolled back to start');
119
120 $schema->txn_commit;
121
122 # And now to see if txn_do will behave correctly
123
124 $schema->txn_do (sub {
125     $schema->txn_do (sub {
126         $arty->name ('Muff');
127
128         $arty->update;
129       });
130
131     eval {
132       $schema->txn_do (sub {
133           $arty->name ('Moff');
134
135           $arty->update;
136
137           $arty->discard_changes;
138
139           is($arty->name,'Moff','Value updated in nested transaction');
140
141           $schema->storage->dbh->do ("GUARANTEED TO PHAIL");
142         });
143     };
144
145     ok ($@,'Nested transaction failed (good)');
146
147     $arty->discard_changes;
148
149     is($arty->name,'Muff','auto_savepoint rollback worked');
150
151     $arty->name ('Miff');
152
153     $arty->update;
154   });
155
156 $arty->discard_changes;
157
158 is($arty->name,'Miff','auto_savepoint worked');
159
160 cmp_ok($stats->{'SVP_BEGIN'},'==',7,'Correct number of savepoints created');
161
162 cmp_ok($stats->{'SVP_RELEASE'},'==',3,'Correct number of savepoints released');
163
164 cmp_ok($stats->{'SVP_ROLLBACK'},'==',5,'Correct number of savepoint rollbacks');
165
166 END { $schema->storage->dbh->do ("DROP TABLE artist") if defined $schema }
167