boltless 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +8 -0
- data/Guardfile +44 -0
- data/Makefile +138 -0
- data/Rakefile +26 -0
- data/docker-compose.yml +19 -0
- data/lib/boltless/configuration.rb +69 -0
- data/lib/boltless/errors/invalid_json_error.rb +9 -0
- data/lib/boltless/errors/request_error.rb +24 -0
- data/lib/boltless/errors/response_error.rb +30 -0
- data/lib/boltless/errors/transaction_begin_error.rb +9 -0
- data/lib/boltless/errors/transaction_in_bad_state_error.rb +11 -0
- data/lib/boltless/errors/transaction_not_found_error.rb +11 -0
- data/lib/boltless/errors/transaction_rollback_error.rb +26 -0
- data/lib/boltless/extensions/configuration_handling.rb +37 -0
- data/lib/boltless/extensions/connection_pool.rb +127 -0
- data/lib/boltless/extensions/operations.rb +175 -0
- data/lib/boltless/extensions/transactions.rb +301 -0
- data/lib/boltless/extensions/utilities.rb +187 -0
- data/lib/boltless/request.rb +386 -0
- data/lib/boltless/result.rb +98 -0
- data/lib/boltless/result_row.rb +90 -0
- data/lib/boltless/statement_collector.rb +40 -0
- data/lib/boltless/transaction.rb +234 -0
- data/lib/boltless/version.rb +23 -0
- data/lib/boltless.rb +36 -0
- data/spec/benchmark/transfer.rb +57 -0
- data/spec/boltless/extensions/configuration_handling_spec.rb +39 -0
- data/spec/boltless/extensions/connection_pool_spec.rb +131 -0
- data/spec/boltless/extensions/operations_spec.rb +189 -0
- data/spec/boltless/extensions/transactions_spec.rb +418 -0
- data/spec/boltless/extensions/utilities_spec.rb +546 -0
- data/spec/boltless/request_spec.rb +946 -0
- data/spec/boltless/result_row_spec.rb +161 -0
- data/spec/boltless/result_spec.rb +127 -0
- data/spec/boltless/statement_collector_spec.rb +45 -0
- data/spec/boltless/transaction_spec.rb +601 -0
- data/spec/boltless_spec.rb +11 -0
- data/spec/fixtures/files/raw_result.yml +21 -0
- data/spec/fixtures/files/raw_result_with_graph_result.yml +48 -0
- data/spec/fixtures/files/raw_result_with_meta.yml +11 -0
- data/spec/fixtures/files/raw_result_with_stats.yml +26 -0
- data/spec/spec_helper.rb +89 -0
- metadata +384 -0
@@ -0,0 +1,601 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Boltless::Transaction do
|
6
|
+
let(:new_instance) { ->(**args) { described_class.new(connection, **args) } }
|
7
|
+
let(:instance) { new_instance.call }
|
8
|
+
let(:connection) { Boltless.connection_pool.checkout }
|
9
|
+
let(:request) { instance.instance_variable_get(:@request) }
|
10
|
+
let(:req_err) { ->(*) { raise Boltless::Errors::RequestError, 'test' } }
|
11
|
+
let(:res_err) { ->(*) { raise Boltless::Errors::ResponseError, 'test' } }
|
12
|
+
let(:raw_state) { nil }
|
13
|
+
|
14
|
+
before do
|
15
|
+
# Only force the raw state when it is configured
|
16
|
+
instance.instance_variable_set(:@raw_state, raw_state) if raw_state
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'full workflow' do
|
20
|
+
let(:opts) { {} }
|
21
|
+
let(:failed_action) do
|
22
|
+
tx = new_instance[**opts]
|
23
|
+
tx.begin
|
24
|
+
tx.run('CREATE (n:User { name: $name })', name: 'Klaus')
|
25
|
+
tx.run('SOME THING!')
|
26
|
+
tx.commit
|
27
|
+
end
|
28
|
+
let(:check_action) do
|
29
|
+
tx = new_instance[**opts]
|
30
|
+
tx.begin
|
31
|
+
tx.run('MATCH (n:User) RETURN n.name').tap do
|
32
|
+
tx.commit
|
33
|
+
end
|
34
|
+
end
|
35
|
+
let(:write_action) do
|
36
|
+
tx = new_instance[**opts]
|
37
|
+
tx.begin!
|
38
|
+
tx.run!('CREATE (n:User { name: $name })', name: 'Klaus')
|
39
|
+
tx.commit!
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'rolls back the transaction on errors' do
|
43
|
+
failed_action
|
44
|
+
expect(check_action.count).to be_eql(0)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'returns a mapped result' do
|
48
|
+
expect(check_action).to be_a(Boltless::Result)
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'with raw results' do
|
52
|
+
let(:opts) { { raw_results: true } }
|
53
|
+
|
54
|
+
it 'returns an unmapped result' do
|
55
|
+
expect(check_action).to be_a(Hash)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'with the read access mode' do
|
60
|
+
let(:opts) { { access_mode: :read } }
|
61
|
+
|
62
|
+
it 'does not allow us to perform write operations' do
|
63
|
+
expect { write_action }.to \
|
64
|
+
raise_error(Boltless::Errors::TransactionRollbackError,
|
65
|
+
/Neo.ClientError.Request.Invalid/i)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'delegations' do
|
71
|
+
it 'allows to access the #build_cypher utility' do
|
72
|
+
expect(instance.respond_to?(:build_cypher)).to be_eql(true)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#initialize' do
|
77
|
+
it 'passes down the connection to the request' do
|
78
|
+
expect(Boltless::Request).to \
|
79
|
+
receive(:new).with(connection, anything)
|
80
|
+
described_class.new(connection)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'passes down the access mode to the request' do
|
84
|
+
expect(Boltless::Request).to \
|
85
|
+
receive(:new).with(connection, a_hash_including(access_mode: :read))
|
86
|
+
described_class.new(connection, access_mode: :read)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'passes down the database to the request' do
|
90
|
+
expect(Boltless::Request).to \
|
91
|
+
receive(:new).with(connection, a_hash_including(database: 'test'))
|
92
|
+
described_class.new(connection, database: 'test')
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'passes down the raw results flag to the request' do
|
96
|
+
expect(Boltless::Request).to \
|
97
|
+
receive(:new).with(connection, a_hash_including(raw_results: true))
|
98
|
+
described_class.new(connection, raw_results: true)
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'with unknown access mode' do
|
102
|
+
it 'raises an ArgumentError' do
|
103
|
+
expect { described_class.new(connection, access_mode: :unknown) }.to \
|
104
|
+
raise_error(
|
105
|
+
ArgumentError,
|
106
|
+
/Unknown access mode 'unknown'.*use ':read' or ':write'/i
|
107
|
+
)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#access_mode' do
|
113
|
+
let(:action) { instance.access_mode }
|
114
|
+
|
115
|
+
context 'when not explictly configured' do
|
116
|
+
it 'returns write' do
|
117
|
+
expect(action).to be_eql(:write)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'when initialized with read' do
|
122
|
+
let(:instance) { new_instance[access_mode: :read] }
|
123
|
+
|
124
|
+
it 'returns read' do
|
125
|
+
expect(action).to be_eql(:read)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'when initialized with write' do
|
130
|
+
let(:instance) { new_instance[access_mode: :write] }
|
131
|
+
|
132
|
+
it 'returns write' do
|
133
|
+
expect(action).to be_eql(:write)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe '#id' do
|
139
|
+
let(:action) { instance.id }
|
140
|
+
|
141
|
+
context 'when not yet started' do
|
142
|
+
it 'returns nil' do
|
143
|
+
expect(action).to be(nil)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'when started' do
|
148
|
+
before { instance.begin! }
|
149
|
+
|
150
|
+
it 'returns an Integer' do
|
151
|
+
expect(action).to be_a(Integer)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe '#raw_state' do
|
157
|
+
let(:action) { instance.raw_state }
|
158
|
+
|
159
|
+
it 'returns an Symbol' do
|
160
|
+
expect(action).to be_a(Symbol)
|
161
|
+
end
|
162
|
+
|
163
|
+
describe 'after initialization' do
|
164
|
+
it 'returns not_yet_started' do
|
165
|
+
expect(action).to be_eql(:not_yet_started)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe '#state' do
|
171
|
+
let(:action) { instance.state }
|
172
|
+
|
173
|
+
it 'returns an ActiveSupport::StringInquirer' do
|
174
|
+
expect(action).to be_a(ActiveSupport::StringInquirer)
|
175
|
+
end
|
176
|
+
|
177
|
+
describe 'after initialization' do
|
178
|
+
it 'returns not_yet_started' do
|
179
|
+
expect(action).to be_eql('not_yet_started')
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe '#begin!' do
|
185
|
+
let(:action) { instance.begin! }
|
186
|
+
let(:instance) { new_instance[access_mode: :read] }
|
187
|
+
|
188
|
+
before { allow(request).to receive(:begin_transaction) }
|
189
|
+
|
190
|
+
context 'when the transaction is not in a usable state' do
|
191
|
+
let(:raw_state) { :closed }
|
192
|
+
|
193
|
+
it 'raises a Boltless::Errors::TransactionInBadStateError' do
|
194
|
+
expect { action }.to \
|
195
|
+
raise_error(Boltless::Errors::TransactionInBadStateError,
|
196
|
+
/Transaction already closed/i)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'call the #begin_transaction on the request' do
|
201
|
+
expect(request).to receive(:begin_transaction).once
|
202
|
+
action
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'returns true' do
|
206
|
+
expect(action).to be_eql(true)
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'switches the state to open' do
|
210
|
+
expect { action }.to \
|
211
|
+
change(instance, :state).from('not_yet_started').to('open')
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe '#begin' do
|
216
|
+
let(:action) { instance.begin }
|
217
|
+
|
218
|
+
context 'when the transaction is not in a usable state' do
|
219
|
+
let(:raw_state) { :closed }
|
220
|
+
|
221
|
+
it 'returns false' do
|
222
|
+
expect(action).to be_eql(false)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'wraps the bang-variant in a #handle_errors call' do
|
227
|
+
expect(instance).to receive(:handle_errors).with(false)
|
228
|
+
action
|
229
|
+
end
|
230
|
+
|
231
|
+
context 'with errors' do
|
232
|
+
before { allow(instance).to receive(:begin!, &res_err) }
|
233
|
+
|
234
|
+
it 'returns false' do
|
235
|
+
expect(action).to be_eql(false)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
context 'without errors' do
|
240
|
+
before { allow(request).to receive(:begin_transaction) }
|
241
|
+
|
242
|
+
it 'returns true' do
|
243
|
+
expect(action).to be_eql(true)
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'switches the state to open' do
|
247
|
+
expect { action }.to \
|
248
|
+
change(instance, :state).from('not_yet_started').to('open')
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
describe '#run!' do
|
254
|
+
let(:action) { instance.run!('RETURN 1') }
|
255
|
+
|
256
|
+
context 'when the transaction is not in a usable state' do
|
257
|
+
let(:raw_state) { :closed }
|
258
|
+
|
259
|
+
it 'raises a Boltless::Errors::TransactionInBadStateError' do
|
260
|
+
expect { action }.to \
|
261
|
+
raise_error(Boltless::Errors::TransactionInBadStateError,
|
262
|
+
/Transaction not open/i)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
context 'with open state' do
|
267
|
+
before { instance.begin! }
|
268
|
+
|
269
|
+
it 'calls the #run_query on the request' do
|
270
|
+
expect(request).to \
|
271
|
+
receive(:run_query).with(instance.id, Hash).and_return([])
|
272
|
+
action
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'returns the result' do
|
276
|
+
res = instance.run!('RETURN date() AS date')
|
277
|
+
expect(res.value).to be_eql(Date.today.to_s)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
describe '#run' do
|
283
|
+
let(:action) { instance.run('RETURN date()') }
|
284
|
+
let(:raw_state) { :open }
|
285
|
+
|
286
|
+
context 'when the transaction is not in a usable state' do
|
287
|
+
let(:raw_state) { :closed }
|
288
|
+
|
289
|
+
it 'returns nil' do
|
290
|
+
expect(action).to be_eql(nil)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'wraps the bang-variant in a #handle_errors call' do
|
295
|
+
expect(instance).to receive(:handle_errors)
|
296
|
+
action
|
297
|
+
end
|
298
|
+
|
299
|
+
context 'with errors' do
|
300
|
+
before { allow(instance).to receive(:run!, &res_err) }
|
301
|
+
|
302
|
+
it 'returns nil' do
|
303
|
+
expect(action).to be_eql(nil)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
context 'without errors' do
|
308
|
+
before { allow(request).to receive(:run_query).and_return([123]) }
|
309
|
+
|
310
|
+
it 'returns an the first result' do
|
311
|
+
expect(action).to be_eql(123)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
describe '#run_in_batch!' do
|
317
|
+
let(:action) { instance.run_in_batch!(['RETURN 1'], ['RETURN date()']) }
|
318
|
+
|
319
|
+
context 'when the transaction is not in a usable state' do
|
320
|
+
let(:raw_state) { :closed }
|
321
|
+
|
322
|
+
it 'raises a Boltless::Errors::TransactionInBadStateError' do
|
323
|
+
expect { action }.to \
|
324
|
+
raise_error(Boltless::Errors::TransactionInBadStateError,
|
325
|
+
/Transaction not open/i)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
context 'with open state' do
|
330
|
+
let(:statements) do
|
331
|
+
[
|
332
|
+
{
|
333
|
+
statement: 'RETURN 1',
|
334
|
+
parameters: {}
|
335
|
+
},
|
336
|
+
{
|
337
|
+
statement: 'RETURN date()',
|
338
|
+
parameters: {}
|
339
|
+
}
|
340
|
+
]
|
341
|
+
end
|
342
|
+
|
343
|
+
before { instance.begin! }
|
344
|
+
|
345
|
+
it 'calls the #run_query on the request' do
|
346
|
+
expect(request).to receive(:run_query).with(instance.id, *statements)
|
347
|
+
action
|
348
|
+
end
|
349
|
+
|
350
|
+
it 'returns two results (one for each statement)' do
|
351
|
+
expect(action.count).to be_eql(2)
|
352
|
+
end
|
353
|
+
|
354
|
+
it 'returns the correct result (first statement)' do
|
355
|
+
expect(action.first.value).to be_eql(1)
|
356
|
+
end
|
357
|
+
|
358
|
+
it 'returns the correct result (second statement)' do
|
359
|
+
expect(action.last.value).to be_eql(Date.today.to_s)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
describe '#run_in_batch' do
|
365
|
+
let(:action) { instance.run_in_batch(['RETURN date()'], ['RETURN 1']) }
|
366
|
+
let(:raw_state) { :open }
|
367
|
+
|
368
|
+
context 'when the transaction is not in a usable state' do
|
369
|
+
let(:raw_state) { :closed }
|
370
|
+
|
371
|
+
it 'returns nil' do
|
372
|
+
expect(action).to be_eql(nil)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
it 'wraps the bang-variant in a #handle_errors call' do
|
377
|
+
expect(instance).to receive(:handle_errors)
|
378
|
+
action
|
379
|
+
end
|
380
|
+
|
381
|
+
context 'with errors' do
|
382
|
+
before { allow(instance).to receive(:run_in_batch!, &res_err) }
|
383
|
+
|
384
|
+
it 'returns nil' do
|
385
|
+
expect(action).to be_eql(nil)
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
context 'without errors' do
|
390
|
+
before { allow(request).to receive(:run_query).and_return([]) }
|
391
|
+
|
392
|
+
it 'returns an empty array' do
|
393
|
+
expect(action).to match_array([])
|
394
|
+
end
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
describe '#commit!' do
|
399
|
+
let(:action) { instance.commit! }
|
400
|
+
let(:instance) { new_instance[access_mode: :read] }
|
401
|
+
|
402
|
+
context 'when the transaction is not in a usable state' do
|
403
|
+
let(:raw_state) { :closed }
|
404
|
+
|
405
|
+
it 'raises a Boltless::Errors::TransactionInBadStateError' do
|
406
|
+
expect { action }.to \
|
407
|
+
raise_error(Boltless::Errors::TransactionInBadStateError,
|
408
|
+
/Transaction not open/i)
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
context 'with open state' do
|
413
|
+
before { instance.begin! }
|
414
|
+
|
415
|
+
it 'calls the #commit_transaction on the request' do
|
416
|
+
expect(request).to receive(:commit_transaction).with(instance.id)
|
417
|
+
action
|
418
|
+
end
|
419
|
+
|
420
|
+
it 'allows to send finalizing statements' do
|
421
|
+
res = instance.commit!(['RETURN date() AS date'])
|
422
|
+
expect(res.first.value).to be_eql(Date.today.to_s)
|
423
|
+
end
|
424
|
+
|
425
|
+
it 'switches the state to closed' do
|
426
|
+
expect { action }.to \
|
427
|
+
change(instance, :state).from('open').to('closed')
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
describe '#commit' do
|
433
|
+
let(:action) { instance.commit }
|
434
|
+
let(:raw_state) { :open }
|
435
|
+
|
436
|
+
context 'when the transaction is not in a usable state' do
|
437
|
+
let(:raw_state) { :closed }
|
438
|
+
|
439
|
+
it 'returns nil' do
|
440
|
+
expect(action).to be_eql(nil)
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
it 'wraps the bang-variant in a #handle_errors call' do
|
445
|
+
expect(instance).to receive(:handle_errors)
|
446
|
+
action
|
447
|
+
end
|
448
|
+
|
449
|
+
context 'with errors' do
|
450
|
+
before { allow(instance).to receive(:commit!, &res_err) }
|
451
|
+
|
452
|
+
it 'returns nil' do
|
453
|
+
expect(action).to be_eql(nil)
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
context 'without errors' do
|
458
|
+
before { allow(request).to receive(:commit_transaction).and_return([]) }
|
459
|
+
|
460
|
+
it 'returns an empty array' do
|
461
|
+
expect(action).to match_array([])
|
462
|
+
end
|
463
|
+
|
464
|
+
it 'switches the state to closed' do
|
465
|
+
expect { action }.to \
|
466
|
+
change(instance, :state).from('open').to('closed')
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
describe '#rollback!' do
|
472
|
+
let(:action) { instance.rollback! }
|
473
|
+
let(:instance) { new_instance[access_mode: :read] }
|
474
|
+
|
475
|
+
context 'when the transaction is not in a usable state' do
|
476
|
+
let(:raw_state) { :closed }
|
477
|
+
|
478
|
+
it 'raises a Boltless::Errors::TransactionInBadStateError' do
|
479
|
+
expect { action }.to \
|
480
|
+
raise_error(Boltless::Errors::TransactionInBadStateError,
|
481
|
+
/Transaction not open/i)
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
context 'with open state' do
|
486
|
+
before { instance.begin! }
|
487
|
+
|
488
|
+
it 'calls the #rollback_transaction on the request' do
|
489
|
+
expect(request).to receive(:rollback_transaction).with(instance.id)
|
490
|
+
action
|
491
|
+
end
|
492
|
+
|
493
|
+
it 'returns true' do
|
494
|
+
expect(action).to be_eql(true)
|
495
|
+
end
|
496
|
+
|
497
|
+
it 'switches the state to closed' do
|
498
|
+
expect { action }.to \
|
499
|
+
change(instance, :state).from('open').to('closed')
|
500
|
+
end
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
describe '#rollback' do
|
505
|
+
let(:action) { instance.rollback }
|
506
|
+
let(:raw_state) { :open }
|
507
|
+
|
508
|
+
context 'when the transaction is not in a usable state' do
|
509
|
+
let(:raw_state) { :closed }
|
510
|
+
|
511
|
+
it 'returns false' do
|
512
|
+
expect(action).to be_eql(false)
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
it 'wraps the bang-variant in a #handle_errors call' do
|
517
|
+
expect(instance).to receive(:handle_errors).with(false)
|
518
|
+
action
|
519
|
+
end
|
520
|
+
|
521
|
+
context 'with errors' do
|
522
|
+
before { allow(instance).to receive(:rollback!, &res_err) }
|
523
|
+
|
524
|
+
it 'returns false' do
|
525
|
+
expect(action).to be_eql(false)
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
context 'without errors' do
|
530
|
+
before { allow(request).to receive(:rollback_transaction) }
|
531
|
+
|
532
|
+
it 'returns true' do
|
533
|
+
expect(action).to be_eql(true)
|
534
|
+
end
|
535
|
+
|
536
|
+
it 'switches the state to closed' do
|
537
|
+
expect { action }.to \
|
538
|
+
change(instance, :state).from('open').to('closed')
|
539
|
+
end
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
describe '#handle_errors' do
|
544
|
+
let(:action) { ->(*args, &block) { instance.handle_errors(*args, &block) } }
|
545
|
+
|
546
|
+
it 'yields the user given block' do
|
547
|
+
expect { |control| action.call(&control) }.to yield_control
|
548
|
+
end
|
549
|
+
|
550
|
+
it 'rescues Boltless::Errors::RequestError' do
|
551
|
+
expect { action.call(&req_err) }.not_to raise_error
|
552
|
+
end
|
553
|
+
|
554
|
+
it 'rescues Boltless::Errors::ResponseError' do
|
555
|
+
expect { action.call(&res_err) }.not_to raise_error
|
556
|
+
end
|
557
|
+
|
558
|
+
it 'does not rescue ArgumentError' do
|
559
|
+
expect { action.call { raise ArgumentError } }.to \
|
560
|
+
raise_error(ArgumentError)
|
561
|
+
end
|
562
|
+
|
563
|
+
it 'returns the given error result in case of errors (non-proc)' do
|
564
|
+
expect(action.call(true, &res_err)).to be_eql(true)
|
565
|
+
end
|
566
|
+
|
567
|
+
it 'returns the given error result in case of errors (proc)' do
|
568
|
+
err_res = ->(e) { "Err: #{e.message}" }
|
569
|
+
expect(action.call(err_res, &res_err)).to be_eql('Err: test')
|
570
|
+
end
|
571
|
+
|
572
|
+
it 'returns the result of the user given block when no errors occur' do
|
573
|
+
expect(action.call { 123 }).to be_eql(123)
|
574
|
+
end
|
575
|
+
|
576
|
+
it 'switches the state to closed on errors' do
|
577
|
+
expect { action.call(&res_err) }.to \
|
578
|
+
change(instance, :state).from('not_yet_started').to('closed')
|
579
|
+
end
|
580
|
+
|
581
|
+
it 'calls #cleanup on errors' do
|
582
|
+
expect(instance).to receive(:cleanup).once
|
583
|
+
action.call(&res_err)
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
587
|
+
describe '#cleanup' do
|
588
|
+
let(:action) { instance.cleanup }
|
589
|
+
|
590
|
+
it 'clears the request instance variable' do
|
591
|
+
expect { action }.to \
|
592
|
+
change { instance.instance_variable_get(:@request) }
|
593
|
+
.from(Boltless::Request).to(nil)
|
594
|
+
end
|
595
|
+
|
596
|
+
it 'changes the state to cleaned' do
|
597
|
+
expect { action }.to \
|
598
|
+
change(instance, :state).from('not_yet_started').to('cleaned')
|
599
|
+
end
|
600
|
+
end
|
601
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# CREATE (n:User { name: $name }) RETURN n [result_as_graph: true]
|
2
|
+
# MATCH (n:User) RETURN n
|
3
|
+
---
|
4
|
+
columns:
|
5
|
+
- n
|
6
|
+
data:
|
7
|
+
- row:
|
8
|
+
- name: Kalle
|
9
|
+
meta:
|
10
|
+
- id: 149
|
11
|
+
type: node
|
12
|
+
deleted: false
|
13
|
+
graph:
|
14
|
+
nodes:
|
15
|
+
- id: '149'
|
16
|
+
labels:
|
17
|
+
- User
|
18
|
+
properties:
|
19
|
+
name: Kalle
|
20
|
+
relationships: []
|
21
|
+
- row:
|
22
|
+
- name: Klaus
|
23
|
+
meta:
|
24
|
+
- id: 147
|
25
|
+
type: node
|
26
|
+
deleted: false
|
27
|
+
graph:
|
28
|
+
nodes:
|
29
|
+
- id: '147'
|
30
|
+
labels:
|
31
|
+
- User
|
32
|
+
properties:
|
33
|
+
name: Klaus
|
34
|
+
relationships: []
|
35
|
+
- row:
|
36
|
+
- name: Bernd
|
37
|
+
meta:
|
38
|
+
- id: 148
|
39
|
+
type: node
|
40
|
+
deleted: false
|
41
|
+
graph:
|
42
|
+
nodes:
|
43
|
+
- id: '148'
|
44
|
+
labels:
|
45
|
+
- User
|
46
|
+
properties:
|
47
|
+
name: Bernd
|
48
|
+
relationships: []
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# CREATE (n:User { name: $name }) RETURN n [with_stats: true]
|
2
|
+
---
|
3
|
+
columns:
|
4
|
+
- n
|
5
|
+
data:
|
6
|
+
- row:
|
7
|
+
- name: Klaus
|
8
|
+
meta:
|
9
|
+
- id: 146
|
10
|
+
type: node
|
11
|
+
deleted: false
|
12
|
+
stats:
|
13
|
+
contains_updates: true
|
14
|
+
nodes_created: 1
|
15
|
+
nodes_deleted: 0
|
16
|
+
properties_set: 1
|
17
|
+
relationships_created: 0
|
18
|
+
relationship_deleted: 0
|
19
|
+
labels_added: 1
|
20
|
+
labels_removed: 0
|
21
|
+
indexes_added: 0
|
22
|
+
indexes_removed: 0
|
23
|
+
constraints_added: 0
|
24
|
+
constraints_removed: 0
|
25
|
+
contains_system_updates: false
|
26
|
+
system_updates: 0
|