@@ -16,9 +16,37 @@ neo4j = require '../'
16
16
17
17
[TEST_NODE_A , TEST_NODE_B , TEST_REL ] = []
18
18
19
+ OPEN_TXS = []
20
+
19
21
20
22
# # HELPERS
21
23
24
+ # To help with cleanup (see below):
25
+ beginTx = ->
26
+ tx = DB .beginTransaction ()
27
+ OPEN_TXS .push tx
28
+ tx
29
+
30
+ # NOTE: Open transactions can cause Neo4j queries & requests to hang,
31
+ # e.g. because a transaction has a lock, or when creating constraints.
32
+ # The default transaction expiry time of 60 seconds is also far too long.
33
+ # So we track all transactions we create (see above), and this method can be
34
+ # called to clean those transactions up whenever needed.
35
+ # It *should* be called at the end at least (see test near end of suite below).
36
+ cleanupTxs = (_ ) ->
37
+ while tx = OPEN_TXS .pop ()
38
+ switch tx .state
39
+ when tx .STATE_COMMITTED , tx .STATE_ROLLED_BACK , tx .STATE_EXPIRED
40
+ continue
41
+ when tx .STATE_PENDING
42
+ throw new Error ' Unexpected: transaction state is pending!
43
+ Maybe a test timed out mid-request?'
44
+ when tx .STATE_OPEN
45
+ tx .rollback _
46
+ expect (tx .state ).to .equal tx .STATE_ROLLED_BACK
47
+ else
48
+ throw new Error " Unrecognized tx state! #{ tx .state } "
49
+
22
50
# Calls the given asynchronous function with a placeholder callback, and
23
51
# immediately returns a "future" that can be called with a real callback.
24
52
# TODO: Achieve this with Streamline futures once we upgrade to 1.0.
@@ -62,14 +90,14 @@ expectTxErrorRolledBack = (tx, _) ->
62
90
describe ' Transactions' , ->
63
91
64
92
it ' should support simple queries' , (_ ) ->
65
- tx = DB . beginTransaction ()
93
+ tx = beginTx ()
66
94
67
95
[{foo}] = tx .cypher ' RETURN "bar" AS foo' , _
68
96
69
97
expect (foo).to .equal ' bar'
70
98
71
99
it ' should convey pending state, and reject concurrent requests' , (done ) ->
72
- tx = DB . beginTransaction ()
100
+ tx = beginTx ()
73
101
expect (tx .state ).to .equal tx .STATE_OPEN
74
102
75
103
fn = ->
@@ -89,7 +117,7 @@ describe 'Transactions', ->
89
117
fixtures .createTestGraph module , 2 , _
90
118
91
119
it ' should isolate effects' , (_ ) ->
92
- tx = DB . beginTransaction ()
120
+ tx = beginTx ()
93
121
94
122
# NOTE: It's important for us to create something new here, rather than
95
123
# modify something existing. Otherwise, since we don't explicitly
@@ -139,7 +167,7 @@ describe 'Transactions', ->
139
167
expect (results).to .be .empty ()
140
168
141
169
it ' should support committing, and reject subsequent requests' , (_ ) ->
142
- tx = DB . beginTransaction ()
170
+ tx = beginTx ()
143
171
144
172
[{nodeA}] = tx .cypher
145
173
query : '''
@@ -173,14 +201,14 @@ describe 'Transactions', ->
173
201
expect (nodeA .properties .test ).to .equal ' committing'
174
202
175
203
it ' should support committing before any queries' , (_ ) ->
176
- tx = DB . beginTransaction ()
204
+ tx = beginTx ()
177
205
expect (tx .state ).to .equal tx .STATE_OPEN
178
206
179
207
tx .commit _
180
208
expect (tx .state ).to .equal tx .STATE_COMMITTED
181
209
182
210
it ' should support auto-committing' , (_ ) ->
183
- tx = DB . beginTransaction ()
211
+ tx = beginTx ()
184
212
185
213
# Rather than test auto-committing on the first query, which doesn't
186
214
# actually create a new transaction, auto-commit on the second.
@@ -234,7 +262,7 @@ describe 'Transactions', ->
234
262
expect (nodeA .properties .i ).to .equal 2
235
263
236
264
it ' should support rolling back, and reject subsequent requests' , (_ ) ->
237
- tx = DB . beginTransaction ()
265
+ tx = beginTx ()
238
266
239
267
[{nodeA}] = tx .cypher
240
268
query : '''
@@ -268,7 +296,7 @@ describe 'Transactions', ->
268
296
expect (nodeA .properties .test ).to .not .equal ' rolling back'
269
297
270
298
it ' should support rolling back before any queries' , (_ ) ->
271
- tx = DB . beginTransaction ()
299
+ tx = beginTx ()
272
300
expect (tx .state ).to .equal tx .STATE_OPEN
273
301
274
302
tx .rollback _
@@ -277,7 +305,7 @@ describe 'Transactions', ->
277
305
# NOTE: Skipping this test by default, because it's slow (we have to pause
278
306
# one second; see note within) and not really a mission-critical feature.
279
307
it .skip ' should support renewing (slow)' , (_ ) ->
280
- tx = DB . beginTransaction ()
308
+ tx = beginTx ()
281
309
282
310
[{nodeA}] = tx .cypher
283
311
query : '''
@@ -320,12 +348,6 @@ describe 'Transactions', ->
320
348
expect (tx .expiresIn ).to .be .greaterThan 0
321
349
expect (tx .expiresIn ).to .equal tx .expiresAt - new Date
322
350
323
- # To prevent Neo4j from hanging at the end waiting for this transaction
324
- # to commit or expire (since it touches the existing graph, and our last
325
- # step is to delete the existing graph), roll this transaction back.
326
- tx .rollback _
327
- expect (tx .state ).to .equal tx .STATE_ROLLED_BACK
328
-
329
351
# We also ensure that renewing didn't cause the transaction to commit.
330
352
[{nodeA}] = DB .cypher
331
353
query : '''
@@ -339,7 +361,7 @@ describe 'Transactions', ->
339
361
expect (nodeA .properties .test ).to .not .equal ' renewing'
340
362
341
363
it ' should properly handle (fatal) client errors' , (_ ) ->
342
- tx = DB . beginTransaction ()
364
+ tx = beginTx ()
343
365
344
366
[{nodeA}] = tx .cypher
345
367
query : '''
@@ -399,8 +421,8 @@ describe 'Transactions', ->
399
421
# We can do this by having two separate transactions take locks on the
400
422
# same two nodes, across two queries, but in opposite order.
401
423
# (Taking a lock on a node just means writing to the node.)
402
- tx1 = DB . beginTransaction ()
403
- tx2 = DB . beginTransaction ()
424
+ tx1 = beginTx ()
425
+ tx2 = beginTx ()
404
426
405
427
[[{nodeA}], [{nodeB}]] = flows .collect _, [
406
428
defer tx1 .cypher .bind tx1,
@@ -481,15 +503,8 @@ describe 'Transactions', ->
481
503
expect (nodeB .properties .test ).to .not .equal ' transient errors'
482
504
expect (nodeB .properties .tx ).to .equal 1
483
505
484
- # To prevent Neo4j from hanging at the end waiting for this transaction
485
- # to commit or expire (since it touches the existing graph, and our last
486
- # step is to delete the existing graph), roll this transaction back.
487
- expect (tx1 .state ).to .equal tx1 .STATE_OPEN
488
- tx1 .rollback _
489
- expect (tx1 .state ).to .equal tx1 .STATE_ROLLED_BACK
490
-
491
506
it ' should properly handle (fatal) database errors' , (_ ) ->
492
- tx = DB . beginTransaction ()
507
+ tx = beginTx ()
493
508
494
509
# Important: don't auto-commit in the first query, because that doesn't
495
510
# let us test that a transaction gets *returned* and *then* rolled back.
@@ -541,7 +556,7 @@ describe 'Transactions', ->
541
556
expect (nodeA .properties .test ).to .not .equal ' database errors'
542
557
543
558
it ' should properly handle (fatal) errors during commit' , (_ ) ->
544
- tx = DB . beginTransaction ()
559
+ tx = beginTx ()
545
560
546
561
# Important: don't auto-commit in the first query, because that doesn't
547
562
# let us test that a transaction gets *returned* and *then* rolled back.
@@ -581,7 +596,7 @@ describe 'Transactions', ->
581
596
expect (tx .state ).to .equal tx .STATE_ROLLED_BACK
582
597
583
598
it ' should properly handle (fatal) errors on the first query' , (_ ) ->
584
- tx = DB . beginTransaction ()
599
+ tx = beginTx ()
585
600
expect (tx .state ).to .equal tx .STATE_OPEN
586
601
587
602
# For precision, implementing this step without Streamline.
@@ -599,7 +614,7 @@ describe 'Transactions', ->
599
614
600
615
it ' should properly handle (fatal) errors
601
616
on an auto-commit first query' , (_ ) ->
602
- tx = DB . beginTransaction ()
617
+ tx = beginTx ()
603
618
expect (tx .state ).to .equal tx .STATE_OPEN
604
619
605
620
# For precision, implementing this step without Streamline.
@@ -618,7 +633,7 @@ describe 'Transactions', ->
618
633
expect (tx .state ).to .equal tx .STATE_ROLLED_BACK
619
634
620
635
it ' should properly handle (fatal) errors with batching' , (_ ) ->
621
- tx = DB . beginTransaction ()
636
+ tx = beginTx ()
622
637
623
638
results = tx .cypher [
624
639
query : '''
@@ -709,5 +724,8 @@ describe 'Transactions', ->
709
724
710
725
it ' should support streaming (TODO)'
711
726
727
+ it ' (clean up open txs)' , (_ ) ->
728
+ cleanupTxs _
729
+
712
730
it ' (delete test graph)' , (_ ) ->
713
731
fixtures .deleteTestGraph module , _
0 commit comments