16
16
17
17
18
18
class BasicView (APIView ):
19
+ database = 'default'
20
+
21
+ def get_queryset (self ):
22
+ return BasicModel .objects .using (self .database ).all ()
23
+
19
24
def post (self , request , * args , ** kwargs ):
20
- BasicModel . objects .create ()
25
+ self . get_queryset () .create ()
21
26
return Response ({'method' : 'GET' })
22
27
23
28
24
- class ErrorView (APIView ):
29
+ class ErrorView (BasicView ):
25
30
def post (self , request , * args , ** kwargs ):
26
- BasicModel . objects .create ()
31
+ self . get_queryset () .create ()
27
32
raise Exception
28
33
29
34
30
- class APIExceptionView (APIView ):
35
+ class APIExceptionView (BasicView ):
31
36
def post (self , request , * args , ** kwargs ):
32
- BasicModel . objects .create ()
37
+ self . get_queryset () .create ()
33
38
raise APIException
34
39
35
40
36
- class NonAtomicAPIExceptionView (APIView ):
41
+ class NonAtomicAPIExceptionView (BasicView ):
37
42
@transaction .non_atomic_requests
38
43
def dispatch (self , * args , ** kwargs ):
39
44
return super ().dispatch (* args , ** kwargs )
40
45
41
46
def get (self , request , * args , ** kwargs ):
42
- BasicModel . objects . all ()
47
+ self . get_queryset ()
43
48
raise Http404
44
49
45
50
@@ -53,34 +58,52 @@ def get(self, request, *args, **kwargs):
53
58
"'atomic' requires transactions and savepoints."
54
59
)
55
60
class DBTransactionTests (TestCase ):
61
+ databases = '__all__'
62
+
56
63
def setUp (self ):
57
- self .view = BasicView .as_view ()
58
- connections .databases ['default' ]['ATOMIC_REQUESTS' ] = True
64
+ self .view = BasicView
65
+ for database in connections .databases :
66
+ connections .databases [database ]['ATOMIC_REQUESTS' ] = True
59
67
60
68
def tearDown (self ):
61
- connections .databases ['default' ]['ATOMIC_REQUESTS' ] = False
69
+ for database in connections .databases :
70
+ connections .databases [database ]['ATOMIC_REQUESTS' ] = False
62
71
63
72
def test_no_exception_commit_transaction (self ):
64
73
request = factory .post ('/' )
65
74
66
75
with self .assertNumQueries (1 ):
67
- response = self .view (request )
76
+ response = self .view . as_view () (request )
68
77
assert not transaction .get_rollback ()
69
78
assert response .status_code == status .HTTP_200_OK
70
79
assert BasicModel .objects .count () == 1
71
80
81
+ def test_no_exception_commit_transaction_spare_connection (self ):
82
+ request = factory .post ('/' )
83
+
84
+ with self .assertNumQueries (1 , using = 'spare' ):
85
+ view = self .view .as_view (database = 'spare' )
86
+ response = view (request )
87
+ assert not transaction .get_rollback (using = 'spare' )
88
+ assert response .status_code == status .HTTP_200_OK
89
+ assert BasicModel .objects .using ('spare' ).count () == 1
90
+
72
91
73
92
@unittest .skipUnless (
74
93
connection .features .uses_savepoints ,
75
94
"'atomic' requires transactions and savepoints."
76
95
)
77
96
class DBTransactionErrorTests (TestCase ):
97
+ databases = '__all__'
98
+
78
99
def setUp (self ):
79
- self .view = ErrorView .as_view ()
80
- connections .databases ['default' ]['ATOMIC_REQUESTS' ] = True
100
+ self .view = ErrorView
101
+ for database in connections .databases :
102
+ connections .databases [database ]['ATOMIC_REQUESTS' ] = True
81
103
82
104
def tearDown (self ):
83
- connections .databases ['default' ]['ATOMIC_REQUESTS' ] = False
105
+ for database in connections .databases :
106
+ connections .databases [database ]['ATOMIC_REQUESTS' ] = False
84
107
85
108
def test_generic_exception_delegate_transaction_management (self ):
86
109
"""
@@ -95,22 +118,37 @@ def test_generic_exception_delegate_transaction_management(self):
95
118
# 2 - insert
96
119
# 3 - release savepoint
97
120
with transaction .atomic ():
98
- self .assertRaises (Exception , self .view , request )
121
+ self .assertRaises (Exception , self .view . as_view () , request )
99
122
assert not transaction .get_rollback ()
100
123
assert BasicModel .objects .count () == 1
101
124
125
+ def test_generic_exception_delegate_transaction_management_spare_connections (self ):
126
+ request = factory .post ('/' )
127
+ with self .assertNumQueries (3 , using = 'spare' ):
128
+ # 1 - begin savepoint
129
+ # 2 - insert
130
+ # 3 - release savepoint
131
+ with transaction .atomic (using = 'spare' ):
132
+ self .assertRaises (Exception , self .view .as_view (database = 'spare' ), request )
133
+ assert not transaction .get_rollback (using = 'spare' )
134
+ assert BasicModel .objects .using ('spare' ).count () == 1
135
+
102
136
103
137
@unittest .skipUnless (
104
138
connection .features .uses_savepoints ,
105
139
"'atomic' requires transactions and savepoints."
106
140
)
107
141
class DBTransactionAPIExceptionTests (TestCase ):
142
+ databases = '__all__'
143
+
108
144
def setUp (self ):
109
- self .view = APIExceptionView .as_view ()
110
- connections .databases ['default' ]['ATOMIC_REQUESTS' ] = True
145
+ self .view = APIExceptionView
146
+ for database in connections .databases :
147
+ connections .databases [database ]['ATOMIC_REQUESTS' ] = True
111
148
112
149
def tearDown (self ):
113
- connections .databases ['default' ]['ATOMIC_REQUESTS' ] = False
150
+ for database in connections .databases :
151
+ connections .databases [database ]['ATOMIC_REQUESTS' ] = False
114
152
115
153
def test_api_exception_rollback_transaction (self ):
116
154
"""
@@ -124,23 +162,44 @@ def test_api_exception_rollback_transaction(self):
124
162
# 3 - rollback savepoint
125
163
# 4 - release savepoint
126
164
with transaction .atomic ():
127
- response = self .view (request )
165
+ response = self .view . as_view () (request )
128
166
assert transaction .get_rollback ()
129
167
assert response .status_code == status .HTTP_500_INTERNAL_SERVER_ERROR
130
168
assert BasicModel .objects .count () == 0
131
169
170
+ def test_api_exception_rollback_transaction_spare_connection (self ):
171
+ """
172
+ Transaction is rollbacked by our transaction atomic block.
173
+ """
174
+ request = factory .post ('/' )
175
+ num_queries = 4 if connections ['spare' ].features .can_release_savepoints else 3
176
+ with self .assertNumQueries (num_queries , using = 'spare' ):
177
+ # 1 - begin savepoint
178
+ # 2 - insert
179
+ # 3 - rollback savepoint
180
+ # 4 - release savepoint
181
+ with transaction .atomic (using = 'spare' ):
182
+ response = self .view .as_view (database = 'spare' )(request )
183
+ assert transaction .get_rollback (using = 'spare' )
184
+ assert response .status_code == status .HTTP_500_INTERNAL_SERVER_ERROR
185
+ assert BasicModel .objects .using ('spare' ).count () == 0
186
+
132
187
133
188
@unittest .skipUnless (
134
189
connection .features .uses_savepoints ,
135
190
"'atomic' requires transactions and savepoints."
136
191
)
137
192
@override_settings (ROOT_URLCONF = 'tests.test_atomic_requests' )
138
193
class NonAtomicDBTransactionAPIExceptionTests (TransactionTestCase ):
194
+ databases = '__all__'
195
+
139
196
def setUp (self ):
140
- connections .databases ['default' ]['ATOMIC_REQUESTS' ] = True
197
+ for database in connections .databases :
198
+ connections .databases [database ]['ATOMIC_REQUESTS' ] = True
141
199
142
200
def tearDown (self ):
143
- connections .databases ['default' ]['ATOMIC_REQUESTS' ] = False
201
+ for database in connections .databases :
202
+ connections .databases [database ]['ATOMIC_REQUESTS' ] = False
144
203
145
204
def test_api_exception_rollback_transaction_non_atomic_view (self ):
146
205
response = self .client .get ('/' )
0 commit comments