em-pg-client 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,17 +11,18 @@ module PGSpecMacros
11
11
  end.should be_a_kind_of ::EM::DefaultDeferrable
12
12
  end
13
13
 
14
- def pg_exec_and_check_with_error(client, err_message, method, *args, &additional_checks)
14
+ def pg_exec_and_check_with_error(client, stop, err_class, err_message, method, *args, &additional_checks)
15
15
  client.__send__(method, *args) do |exception|
16
- exception.should be_an_instance_of PG::Error
16
+ exception.should be_an_instance_of err_class
17
17
  exception.to_s.should include err_message if err_message
18
18
  additional_checks.call(exception) if additional_checks
19
- EM.stop
19
+ EM.next_tick { EM.stop } if stop
20
20
  end.should be_a_kind_of ::EM::DefaultDeferrable
21
21
  end
22
22
 
23
23
  def ensure_em_stop
24
24
  yield
25
+ ensure
25
26
  EM.stop
26
27
  end
27
28
 
@@ -32,18 +33,18 @@ module PGSpecMacros
32
33
  end
33
34
  end
34
35
 
35
- def it_should_execute_with_error(text, err_message, method, *args)
36
+ def it_should_execute_with_error(text, err_class, err_message, method, *args)
36
37
  it "should #{text}" do
37
- pg_exec_and_check_with_error(@client, err_message, method, *args)
38
+ pg_exec_and_check_with_error(@client, true, err_class, err_message, method, *args)
38
39
  end
39
40
  end
40
41
 
41
42
  def it_should_rollback
42
- it_should_execute("rollback transaction", :query, 'ROLLBACK')
43
+ it_should_execute("rollback transaction", :query_defer, 'ROLLBACK')
43
44
  end
44
45
 
45
46
  def it_should_begin
46
- it_should_execute("begin transaction", :query, 'BEGIN TRANSACTION')
47
+ it_should_execute("begin transaction", :query_defer, 'BEGIN TRANSACTION')
47
48
  end
48
49
  end
49
50
  end
@@ -87,36 +88,6 @@ shared_context 'em-pg common before' do
87
88
  end
88
89
  end
89
90
 
90
- it "should set async_autoreconnect according to on_autoreconnect" do
91
- ensure_em_stop do
92
- on_autoreconnect = proc {|c, e| false }
93
- async_args = described_class.parse_async_args([])
94
- async_args.should be_an_instance_of Hash
95
- async_args[:@on_autoreconnect].should be_nil
96
- async_args[:@async_autoreconnect].should be_false
97
- args = [on_autoreconnect: on_autoreconnect]
98
- async_args = described_class.parse_async_args(args)
99
- args.should eq [{}]
100
- async_args.should be_an_instance_of Hash
101
- async_args[:@on_autoreconnect].should be on_autoreconnect
102
- async_args[:@async_autoreconnect].should be_true
103
- args = [async_autoreconnect: false,
104
- on_autoreconnect: on_autoreconnect]
105
- async_args = described_class.parse_async_args(args)
106
- args.should eq [{}]
107
- async_args.should be_an_instance_of Hash
108
- async_args[:@on_autoreconnect].should be on_autoreconnect
109
- async_args[:@async_autoreconnect].should be_false
110
- args = [on_autoreconnect: on_autoreconnect,
111
- async_autoreconnect: false]
112
- async_args = described_class.parse_async_args(args)
113
- args.should eq [{}]
114
- async_args.should be_an_instance_of Hash
115
- async_args[:@on_autoreconnect].should be on_autoreconnect
116
- async_args[:@async_autoreconnect].should be_false
117
- end
118
- end
119
-
120
91
  it "should have same internal and external encoding" do
121
92
  ensure_em_stop do
122
93
  @client.external_encoding.should be @client.internal_encoding
@@ -126,20 +97,20 @@ shared_context 'em-pg common before' do
126
97
  it_should_begin
127
98
 
128
99
  it_should_execute("drop table `foo` if exists",
129
- :query, 'DROP TABLE IF EXISTS foo')
100
+ :query_defer, 'DROP TABLE IF EXISTS foo')
130
101
 
131
102
  it_should_execute("create simple table `foo`",
132
- :query, 'CREATE TABLE foo (id integer,cdate timestamp with time zone,data varchar)')
103
+ :query_defer, 'CREATE TABLE foo (id integer,cdate timestamp with time zone,data varchar)')
133
104
 
134
105
  end
135
106
 
136
107
  shared_context 'em-pg common after' do
137
108
 
138
109
  it_should_execute("create prepared statement",
139
- :prepare, 'get_foo', 'SELECT * FROM foo order by id')
110
+ :prepare_defer, 'get_foo', 'SELECT * FROM foo order by id')
140
111
 
141
112
  it "should describe prepared statement" do
142
- pg_exec_and_check(@client, :describe_prepared, 'get_foo') do |result|
113
+ pg_exec_and_check(@client, :describe_prepared_defer, 'get_foo') do |result|
143
114
  result.nfields.should eq 3
144
115
  result.fname(0).should eq 'id'
145
116
  result.values.should be_empty
@@ -147,7 +118,7 @@ shared_context 'em-pg common after' do
147
118
  end
148
119
 
149
120
  it "should read foo table with prepared statement" do
150
- pg_exec_and_check(@client, :exec_prepared, 'get_foo') do |result|
121
+ pg_exec_and_check(@client, :exec_prepared_defer, 'get_foo') do |result|
151
122
  result.each_with_index do |row, i|
152
123
  row['id'].to_i.should == i
153
124
  DateTime.parse(row['cdate']).should == @cdates[i]
@@ -157,10 +128,10 @@ shared_context 'em-pg common after' do
157
128
  end
158
129
 
159
130
  it_should_execute("declare cursor",
160
- :query, 'DECLARE foobar SCROLL CURSOR FOR SELECT * FROM foo')
131
+ :query_defer, 'DECLARE foobar SCROLL CURSOR FOR SELECT * FROM foo')
161
132
 
162
133
  it "should fetch two rows from table" do
163
- pg_exec_and_check(@client, :query, 'FETCH FORWARD 2 FROM foobar') do |result|
134
+ pg_exec_and_check(@client, :query_defer, 'FETCH FORWARD 2 FROM foobar') do |result|
164
135
  result.nfields.should eq 3
165
136
  result.fname(0).should eq 'id'
166
137
  result.values.length.should eq 2
@@ -168,25 +139,25 @@ shared_context 'em-pg common after' do
168
139
  end
169
140
 
170
141
  it "should describe cursor with describe_portal" do
171
- pg_exec_and_check(@client, :describe_portal, 'foobar') do |result|
142
+ pg_exec_and_check(@client, :describe_portal_defer, 'foobar') do |result|
172
143
  result.nfields.should eq 3
173
144
  result.fname(0).should eq 'id'
174
145
  end
175
146
  end
176
147
 
177
- it_should_execute("close cursor", :query, 'CLOSE foobar')
148
+ it_should_execute("close cursor", :query_defer, 'CLOSE foobar')
178
149
 
179
150
  it "should connect to database asynchronously" do
180
151
  this = :first
181
152
  Encoding.default_internal = Encoding::ISO_8859_1
182
- described_class.async_connect do |conn|
153
+ described_class.connect_defer do |conn|
183
154
  this = :second
184
155
  Encoding.default_internal = nil
185
156
  conn.should be_an_instance_of described_class
186
157
  conn.external_encoding.should_not eq(conn.internal_encoding)
187
158
  conn.internal_encoding.should be Encoding::ISO_8859_1
188
159
  conn.get_client_encoding.should eq "LATIN1"
189
- pg_exec_and_check(conn, :query, 'SELECT pg_database_size(current_database());') do |result|
160
+ pg_exec_and_check(conn, :query_defer, 'SELECT pg_database_size(current_database());') do |result|
190
161
  result[0]['pg_database_size'].to_i.should be > 0
191
162
  end
192
163
  end.should be_a_kind_of ::EM::DefaultDeferrable
@@ -196,7 +167,7 @@ shared_context 'em-pg common after' do
196
167
  it "should connect without setting incompatible encoding" do
197
168
  this = :first
198
169
  Encoding.default_internal = Encoding::Emacs_Mule
199
- described_class.async_connect do |conn|
170
+ described_class.connect_defer do |conn|
200
171
  this = :second
201
172
  Encoding.default_internal = nil
202
173
  conn.should be_an_instance_of described_class
@@ -207,13 +178,14 @@ shared_context 'em-pg common after' do
207
178
  end
208
179
 
209
180
  it_should_execute_with_error("raise syntax error in misspelled multiple statement",
181
+ PG::SyntaxError,
210
182
  "syntax error",
211
- :query, 'SELECT * from pg_class; SRELECT CURRENT_TIMESTAMP; SELECT 42 number')
183
+ :query_defer, 'SELECT * from pg_class; SRELECT CURRENT_TIMESTAMP; SELECT 42 number')
212
184
 
213
185
  it_should_rollback
214
186
 
215
187
  it "should return only last statement" do
216
- pg_exec_and_check(@client, :query,
188
+ pg_exec_and_check(@client, :query_defer,
217
189
  'SELECT * from pg_class; SELECT CURRENT_TIMESTAMP; SELECT 42 number') do |result|
218
190
  result[0]['number'].should eq "42"
219
191
  end
@@ -224,12 +196,20 @@ shared_context 'em-pg common after' do
224
196
  @client.query_timeout = 1.5
225
197
  @client.query_timeout.should eq 1.5
226
198
  start_time = Time.now
227
- pg_exec_and_check_with_error(@client, "query timeout expired", :query, 'SELECT pg_sleep(2)') do
199
+ pg_exec_and_check_with_error(@client, false,
200
+ PG::ConnectionBad, "query timeout expired",
201
+ :query_defer, 'SELECT pg_sleep(2)') do
228
202
  (Time.now - start_time).should be < 2
229
203
  @client.async_command_aborted.should be_true
230
204
  @client.status.should be PG::CONNECTION_BAD
231
205
  @client.query_timeout = 0
232
206
  @client.query_timeout.should eq 0
207
+ @client.async_autoreconnect = false
208
+ pg_exec_and_check_with_error(@client, true,
209
+ PG::ConnectionBad, "previous query expired",
210
+ :query_defer, 'SELECT 1') do
211
+ @client.async_autoreconnect = true
212
+ end
233
213
  end
234
214
  end
235
215
 
@@ -238,7 +218,7 @@ shared_context 'em-pg common after' do
238
218
  @client.query_timeout = 1.1
239
219
  @client.query_timeout.should eq 1.1
240
220
  start_time = Time.now
241
- pg_exec_and_check(@client, :query,
221
+ pg_exec_and_check(@client, :query_defer,
242
222
  'SELECT * from pg_class;' +
243
223
  'SELECT pg_sleep(1);' +
244
224
  'SELECT * from pg_class;' +
@@ -258,7 +238,9 @@ shared_context 'em-pg common after' do
258
238
  @client.query_timeout = 1.1
259
239
  @client.query_timeout.should eq 1.1
260
240
  start_time = Time.now
261
- pg_exec_and_check_with_error(@client, "query timeout expired", :query,
241
+ pg_exec_and_check_with_error(@client, true,
242
+ PG::ConnectionBad, "query timeout expired",
243
+ :query_defer,
262
244
  'SELECT * from pg_class;' +
263
245
  'SELECT pg_sleep(1);' +
264
246
  'SELECT * from pg_class;' +
@@ -281,4 +263,23 @@ shared_context 'em-pg common after' do
281
263
  @client.status.should be PG::CONNECTION_OK
282
264
  end
283
265
  end
266
+
267
+ it "should not expire after executing erraneous query" do
268
+ @client.query_timeout.should eq 0
269
+ @client.query_timeout = 0.1
270
+ @client.query_timeout.should eq 0.1
271
+ start_time = Time.now
272
+ pg_exec_and_check_with_error(@client, false,
273
+ PG::SyntaxError, "syntax error",
274
+ :query_defer, 'SELLECT 1') do
275
+ @client.async_command_aborted.should be_false
276
+ ::EM.add_timer(0.11) do
277
+ @client.async_command_aborted.should be_false
278
+ @client.status.should be PG::CONNECTION_OK
279
+ @client.query_timeout = 0
280
+ @client.query_timeout.should eq 0
281
+ EM.stop
282
+ end
283
+ end
284
+ end
284
285
  end
@@ -1,8 +1,9 @@
1
1
  $:.unshift "lib"
2
+ gem 'eventmachine', '~> 1.0.0'
2
3
  gem 'pg', ENV['EM_PG_CLIENT_TEST_PG_VERSION']
3
4
  require 'date'
4
5
  require 'em-synchrony'
5
- require 'em-synchrony/pg'
6
+ require 'pg/em'
6
7
 
7
8
  describe PG::EM::Client do
8
9
 
@@ -41,7 +42,7 @@ describe PG::EM::Client do
41
42
 
42
43
  it "should populate foo with some data " do
43
44
  results = @values.map do |(data, id)|
44
- @client.query('INSERT INTO foo (id,cdate,data) VALUES($1,$2,$3) returning cdate', [id, DateTime.now, data]) do |result|
45
+ @client.exec_params('INSERT INTO foo (id,cdate,data) VALUES($1,$2,$3) returning cdate', [id, DateTime.now, data]) do |result|
45
46
  result.should be_an_instance_of PG::Result
46
47
  DateTime.parse(result[0]['cdate'])
47
48
  end
@@ -166,7 +167,7 @@ describe PG::EM::Client do
166
167
  it "should raise syntax error in misspelled multiple statement" do
167
168
  expect {
168
169
  @client.query('SELECT * from pg_class; SRELECT CURRENT_TIMESTAMP; SELECT 42 number')
169
- }.to raise_error(PG::Error, /syntax error/)
170
+ }.to raise_error(PG::SyntaxError, /syntax error/)
170
171
  end
171
172
 
172
173
  it "should rollback transaction" do
@@ -189,12 +190,17 @@ describe PG::EM::Client do
189
190
  start_time = Time.now
190
191
  expect {
191
192
  @client.query('SELECT pg_sleep(2)')
192
- }.to raise_error(PG::Error, /query timeout expired/)
193
+ }.to raise_error(PG::ConnectionBad, /query timeout expired/)
193
194
  (Time.now - start_time).should be < 2
194
195
  @client.query_timeout = 0
195
196
  @client.query_timeout.should eq 0
196
197
  @client.async_command_aborted.should be_true
197
198
  @client.status.should be PG::CONNECTION_BAD
199
+ @client.async_autoreconnect = false
200
+ expect {
201
+ @client.query('SELECT 1')
202
+ }.to raise_error(PG::ConnectionBad, /previous query expired/)
203
+ @client.async_autoreconnect = true
198
204
  end
199
205
 
200
206
  it "should timeout not expire while executing query with partial results" do
@@ -230,7 +236,7 @@ describe PG::EM::Client do
230
236
  'SELECT * from pg_class;' +
231
237
  'SELECT pg_sleep(2);' +
232
238
  'SELECT 42 number')
233
- }.to raise_error(PG::Error, /query timeout expired/)
239
+ }.to raise_error(PG::ConnectionBad, /query timeout expired/)
234
240
  (Time.now - start_time).should be > 2
235
241
  @client.async_command_aborted.should be_true
236
242
  @client.status.should be PG::CONNECTION_BAD
@@ -248,6 +254,249 @@ describe PG::EM::Client do
248
254
  end
249
255
  end
250
256
 
257
+ it "should not expire after executing erraneous query" do
258
+ @client.query_timeout.should eq 0
259
+ @client.query_timeout = 0.1
260
+ @client.query_timeout.should eq 0.1
261
+ expect {
262
+ @client.query('SELLECT 1')
263
+ }.to raise_error(PG::SyntaxError, /syntax error/)
264
+ @client.async_command_aborted.should be_false
265
+ @client.status.should be PG::CONNECTION_OK
266
+ ::EM::Synchrony.sleep 0.11
267
+ @client.async_command_aborted.should be_false
268
+ @client.status.should be PG::CONNECTION_OK
269
+ end
270
+
271
+ describe 'PG::EM::Client#transaction' do
272
+
273
+ it "should raise ArgumentError when there is no block" do
274
+ expect do
275
+ @client.transaction
276
+ end.to raise_error(ArgumentError, /Must supply block for PG::EM::Client#transaction/)
277
+ end
278
+
279
+ it "should commit transaction and return whatever block yields" do
280
+ @client.transaction_status.should be PG::PQTRANS_IDLE
281
+ @client.transaction do |pg|
282
+ pg.should be @client
283
+ @client.transaction_status.should be PG::PQTRANS_INTRANS
284
+ @client.instance_variable_get(:@client_tran_count).should eq 1
285
+ @client.query(
286
+ 'DROP TABLE IF EXISTS bar'
287
+ ).should be_an_instance_of PG::Result
288
+ @client.query(
289
+ 'CREATE TABLE bar (key integer, value varchar)'
290
+ ).should be_an_instance_of PG::Result
291
+ @client.query("INSERT INTO bar (key,value) VALUES(42,'xyz') returning value") do |result|
292
+ result.should be_an_instance_of PG::Result
293
+ result[0]['value']
294
+ end
295
+ end.should eq 'xyz'
296
+ @client.query('SELECT * FROM bar') do |result|
297
+ result.should be_an_instance_of PG::Result
298
+ result[0]['key'].should eq '42'
299
+ end
300
+ @client.transaction_status.should be PG::PQTRANS_IDLE
301
+ @client.instance_variable_get(:@client_tran_count).should eq 0
302
+ end
303
+
304
+ it "should rollback transaction on error and raise that error" do
305
+ @client.transaction_status.should be PG::PQTRANS_IDLE
306
+ expect do
307
+ @client.transaction do |pg|
308
+ pg.should be @client
309
+ @client.transaction_status.should be PG::PQTRANS_INTRANS
310
+ @client.instance_variable_get(:@client_tran_count).should eq 1
311
+ @client.query(
312
+ "INSERT INTO bar (key,value) VALUES(11,'abc')"
313
+ ).should be_an_instance_of PG::Result
314
+ @client.query('SELECT * FROM bar ORDER BY key') do |result|
315
+ result.should be_an_instance_of PG::Result
316
+ result[0]['key'].should eq '11'
317
+ end
318
+ @client.query('SELECT count(*) AS count FROM bar') do |result|
319
+ result.should be_an_instance_of PG::Result
320
+ result[0]['count'].should eq '2'
321
+ end
322
+ raise "rollback"
323
+ end
324
+ end.to raise_error(RuntimeError, /rollback/)
325
+ @client.query('SELECT count(*) AS count FROM bar') do |result|
326
+ result.should be_an_instance_of PG::Result
327
+ result[0]['count'].should eq '1'
328
+ end
329
+ @client.transaction_status.should be PG::PQTRANS_IDLE
330
+ @client.instance_variable_get(:@client_tran_count).should eq 0
331
+ end
332
+
333
+ it "should allow nesting transaction and return whatever innermost block yields" do
334
+ @client.transaction_status.should be PG::PQTRANS_IDLE
335
+ @client.transaction do |pg|
336
+ pg.should be @client
337
+ @client.transaction_status.should be PG::PQTRANS_INTRANS
338
+ @client.instance_variable_get(:@client_tran_count).should eq 1
339
+ @client.query(
340
+ "INSERT INTO bar (key,value) VALUES(100,'hundred') returning value"
341
+ ).should be_an_instance_of PG::Result
342
+ @client.transaction do |pg|
343
+ pg.should be @client
344
+ @client.transaction_status.should be PG::PQTRANS_INTRANS
345
+ @client.instance_variable_get(:@client_tran_count).should eq 2
346
+ @client.query(
347
+ "INSERT INTO bar (key,value) VALUES(1000,'thousand') returning value"
348
+ ).should be_an_instance_of PG::Result
349
+ @client.transaction do |pg|
350
+ pg.should be @client
351
+ @client.transaction_status.should be PG::PQTRANS_INTRANS
352
+ @client.instance_variable_get(:@client_tran_count).should eq 3
353
+ @client.query("INSERT INTO bar (key,value) VALUES(1000000,'million') returning value")
354
+ end
355
+ end
356
+ end.tap do |result|
357
+ result.should be_an_instance_of PG::Result
358
+ result[0]['value'].should eq 'million'
359
+ end
360
+ @client.query('SELECT key,value FROM bar ORDER BY key') do |result|
361
+ result.should be_an_instance_of PG::Result
362
+ result.column_values(0).should eq ['42','100','1000','1000000']
363
+ result.column_values(1).should eq ['xyz','hundred','thousand','million']
364
+ end
365
+ @client.transaction_status.should be PG::PQTRANS_IDLE
366
+ @client.instance_variable_get(:@client_tran_count).should eq 0
367
+ end
368
+
369
+ it "should allow nesting transaction and rollback on error" do
370
+ @client.transaction_status.should be PG::PQTRANS_IDLE
371
+ expect do
372
+ @client.transaction do |pg|
373
+ pg.should be @client
374
+ @client.transaction_status.should be PG::PQTRANS_INTRANS
375
+ @client.instance_variable_get(:@client_tran_count).should eq 1
376
+ @client.query(
377
+ "INSERT INTO bar (key,value) VALUES(200,'two hundred') returning value"
378
+ ).should be_an_instance_of PG::Result
379
+ @client.transaction do |pg|
380
+ pg.should be @client
381
+ @client.transaction_status.should be PG::PQTRANS_INTRANS
382
+ @client.instance_variable_get(:@client_tran_count).should eq 2
383
+ @client.query(
384
+ "INSERT INTO bar (key,value) VALUES(2000,'two thousands') returning value"
385
+ ).should be_an_instance_of PG::Result
386
+ @client.transaction do |pg|
387
+ pg.should be @client
388
+ @client.transaction_status.should be PG::PQTRANS_INTRANS
389
+ @client.instance_variable_get(:@client_tran_count).should eq 3
390
+ @client.query(
391
+ "INSERT INTO bar (key,value) VALUES(2000000,'two millions') returning value"
392
+ ).should be_an_instance_of PG::Result
393
+ raise "rollback from here"
394
+ end
395
+ end
396
+ end
397
+ end.to raise_error(RuntimeError, /rollback from here/)
398
+ @client.query('SELECT key,value FROM bar ORDER BY key') do |result|
399
+ result.should be_an_instance_of PG::Result
400
+ result.column_values(0).should eq ['42','100','1000','1000000']
401
+ result.column_values(1).should eq ['xyz','hundred','thousand','million']
402
+ end
403
+ @client.transaction_status.should be PG::PQTRANS_IDLE
404
+ @client.instance_variable_get(:@client_tran_count).should eq 0
405
+ end
406
+
407
+ it "should allow rollback on rescued sql error from nested transaction" do
408
+ flag = false
409
+ @client.transaction_status.should be PG::PQTRANS_IDLE
410
+ @client.transaction do |pg|
411
+ pg.should be @client
412
+ @client.transaction_status.should be PG::PQTRANS_INTRANS
413
+ @client.instance_variable_get(:@client_tran_count).should eq 1
414
+ @client.query(
415
+ "INSERT INTO bar (key,value) VALUES(300,'three hundred') returning value"
416
+ ).should be_an_instance_of PG::Result
417
+ @client.transaction do |pg|
418
+ pg.should be @client
419
+ @client.transaction_status.should be PG::PQTRANS_INTRANS
420
+ @client.instance_variable_get(:@client_tran_count).should eq 2
421
+ @client.query(
422
+ "INSERT INTO bar (key,value) VALUES(3000,'three thousands') returning value"
423
+ ).should be_an_instance_of PG::Result
424
+ @client.transaction do |pg|
425
+ pg.should be @client
426
+ @client.transaction_status.should be PG::PQTRANS_INTRANS
427
+ @client.instance_variable_get(:@client_tran_count).should eq 3
428
+ expect {
429
+ @client.query('SRELECT CURRENT_TIMESTAMP')
430
+ }.to raise_error(PG::SyntaxError, /syntax error/)
431
+ @client.transaction_status.should be PG::PQTRANS_INERROR
432
+ @client.instance_variable_get(:@client_tran_count).should eq 3
433
+ expect {
434
+ @client.query('SELECT CURRENT_TIMESTAMP')
435
+ }.to raise_error(PG::InFailedSqlTransaction, /transaction is aborted/)
436
+ @client.transaction_status.should be PG::PQTRANS_INERROR
437
+ @client.instance_variable_get(:@client_tran_count).should eq 3
438
+ expect do
439
+ @client.transaction { 'foo' }
440
+ end.to raise_error(PG::InFailedSqlTransaction, /transaction is aborted/)
441
+ @client.transaction_status.should be PG::PQTRANS_INERROR
442
+ @client.instance_variable_get(:@client_tran_count).should eq 3
443
+ flag = :was_here
444
+ end
445
+ @client.transaction_status.should be PG::PQTRANS_INERROR
446
+ @client.instance_variable_get(:@client_tran_count).should eq 2
447
+ expect {
448
+ @client.query('SELECT CURRENT_TIMESTAMP')
449
+ }.to raise_error(PG::InFailedSqlTransaction, /transaction is aborted/)
450
+ expect do
451
+ @client.transaction { 'foo' }
452
+ end.to raise_error(PG::InFailedSqlTransaction, /transaction is aborted/)
453
+ @client.transaction_status.should be PG::PQTRANS_INERROR
454
+ @client.instance_variable_get(:@client_tran_count).should eq 2
455
+ end
456
+ @client.transaction_status.should be PG::PQTRANS_INERROR
457
+ @client.instance_variable_get(:@client_tran_count).should eq 1
458
+ expect {
459
+ @client.query('SELECT CURRENT_TIMESTAMP')
460
+ }.to raise_error(PG::InFailedSqlTransaction, /transaction is aborted/)
461
+ expect do
462
+ @client.transaction { 'foo' }
463
+ end.to raise_error(PG::InFailedSqlTransaction, /transaction is aborted/)
464
+ @client.transaction_status.should be PG::PQTRANS_INERROR
465
+ @client.instance_variable_get(:@client_tran_count).should eq 1
466
+ end
467
+ @client.transaction_status.should be PG::PQTRANS_IDLE
468
+ @client.instance_variable_get(:@client_tran_count).should eq 0
469
+ @client.transaction { 'foo' }.should eq 'foo'
470
+ @client.query('SELECT key,value FROM bar ORDER BY key') do |result|
471
+ result.should be_an_instance_of PG::Result
472
+ result.column_values(0).should eq ['42','100','1000','1000000']
473
+ result.column_values(1).should eq ['xyz','hundred','thousand','million']
474
+ end
475
+ flag.should be :was_here
476
+ end
477
+
478
+ it "should detect premature transaction state change" do
479
+ flag = false
480
+ @client.transaction_status.should be PG::PQTRANS_IDLE
481
+ @client.instance_variable_get(:@client_tran_count).should eq 0
482
+ @client.transaction do |pg|
483
+ pg.should be @client
484
+ @client.transaction_status.should be PG::PQTRANS_INTRANS
485
+ @client.query('ROLLBACK')
486
+ @client.instance_variable_get(:@client_tran_count).should eq 1
487
+ @client.transaction_status.should be PG::PQTRANS_IDLE
488
+ @client.transaction do
489
+ @client.transaction_status.should be PG::PQTRANS_INTRANS
490
+ @client.instance_variable_get(:@client_tran_count).should eq 1
491
+ 'foo'
492
+ end.should eq 'foo'
493
+ @client.transaction_status.should be PG::PQTRANS_IDLE
494
+ @client.instance_variable_get(:@client_tran_count).should eq 0
495
+ end
496
+ @client.instance_variable_get(:@client_tran_count).should eq 0
497
+ end
498
+ end
499
+
251
500
  around(:each) do |testcase|
252
501
  @after_em_stop = nil
253
502
  EM.synchrony do