master_slave_adapter 0.2.0 → 1.0.0.beta1
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.
- data/.travis.yml +1 -0
- data/CHANGELOG.md +11 -0
- data/TODO.txt +14 -4
- data/lib/active_record/connection_adapters/master_slave_adapter/circuit_breaker.rb +61 -0
- data/lib/active_record/connection_adapters/master_slave_adapter/clock.rb +42 -0
- data/lib/active_record/connection_adapters/master_slave_adapter/version.rb +7 -0
- data/lib/active_record/connection_adapters/master_slave_adapter.rb +501 -1
- data/lib/active_record/connection_adapters/mysql_master_slave_adapter.rb +72 -1
- data/lib/master_slave_adapter.rb +1 -624
- data/master_slave_adapter.gemspec +8 -6
- data/spec/circuit_breaker_spec.rb +52 -0
- data/spec/master_slave_adapter_spec.rb +48 -293
- data/spec/mysql_master_slave_adapter_spec.rb +320 -0
- metadata +16 -8
- data/VERSION +0 -1
@@ -1,21 +1,23 @@
|
|
1
1
|
$:.push File.expand_path("../lib", __FILE__)
|
2
2
|
|
3
|
+
require 'active_record/connection_adapters/master_slave_adapter/version'
|
4
|
+
|
3
5
|
Gem::Specification.new do |s|
|
4
6
|
s.name = 'master_slave_adapter'
|
5
|
-
s.version =
|
7
|
+
s.version = ActiveRecord::ConnectionAdapters::MasterSlaveAdapter::VERSION
|
6
8
|
s.platform = Gem::Platform::RUBY
|
7
|
-
s.authors = [ 'Mauricio Linhares', 'Torsten Curdt', 'Kim Altintop', 'Omid Aladini', 'SoundCloud' ]
|
8
|
-
s.email = %q{kim@soundcloud.com tcurdt@soundcloud.com
|
9
|
+
s.authors = [ 'Mauricio Linhares', 'Torsten Curdt', 'Kim Altintop', 'Omid Aladini', 'Tiago Loureiro', 'Tobias Schmidt', 'SoundCloud' ]
|
10
|
+
s.email = %q{kim@soundcloud.com tcurdt@soundcloud.com ts@soundcloud}
|
9
11
|
s.homepage = 'http://github.com/soundcloud/master_slave_adapter'
|
10
|
-
s.summary = %q{Replication Aware Master/Slave Database Adapter for
|
11
|
-
s.description = %q{(MySQL) Replication Aware Master/Slave Database Adapter for
|
12
|
+
s.summary = %q{Replication Aware Master/Slave Database Adapter for ActiveRecord}
|
13
|
+
s.description = %q{(MySQL) Replication Aware Master/Slave Database Adapter for ActiveRecord}
|
12
14
|
|
13
15
|
s.files = `git ls-files`.split("\n")
|
14
16
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
17
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
18
|
s.require_path = 'lib'
|
17
19
|
|
18
|
-
s.required_ruby_version = '>= 1.
|
20
|
+
s.required_ruby_version = '>= 1.8.7'
|
19
21
|
s.required_rubygems_version = '>= 1.3.7'
|
20
22
|
|
21
23
|
s.add_development_dependency 'rspec'
|
@@ -0,0 +1,52 @@
|
|
1
|
+
$: << File.expand_path(File.join(File.dirname( __FILE__ ), '..', 'lib'))
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'active_record/connection_adapters/master_slave_adapter/circuit_breaker'
|
5
|
+
|
6
|
+
describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter::CircuitBreaker do
|
7
|
+
let(:logger) { nil }
|
8
|
+
let(:failure_threshold) { 5 }
|
9
|
+
let(:timeout) { 10 }
|
10
|
+
|
11
|
+
subject { described_class.new(logger, failure_threshold, timeout) }
|
12
|
+
|
13
|
+
it 'should not be tripped by default' do
|
14
|
+
should_not be_tripped
|
15
|
+
end
|
16
|
+
|
17
|
+
context "after single failure" do
|
18
|
+
before { subject.fail! }
|
19
|
+
|
20
|
+
it 'should remain untripped' do
|
21
|
+
should_not be_tripped
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "after failure threshold is reached" do
|
26
|
+
before { failure_threshold.times { subject.fail! } }
|
27
|
+
|
28
|
+
it { should be_tripped }
|
29
|
+
|
30
|
+
context "and timeout exceeded" do
|
31
|
+
before do
|
32
|
+
now = Time.now
|
33
|
+
Time.stub(:now).and_return(now + timeout)
|
34
|
+
subject.tripped? # side effect :/
|
35
|
+
end
|
36
|
+
|
37
|
+
it { should_not be_tripped }
|
38
|
+
|
39
|
+
context "after single failure" do
|
40
|
+
before { subject.fail! }
|
41
|
+
|
42
|
+
it { should be_tripped }
|
43
|
+
end
|
44
|
+
|
45
|
+
context "after single success" do
|
46
|
+
before { subject.success! }
|
47
|
+
|
48
|
+
it { should_not be_tripped }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -1,18 +1,35 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
|
3
3
|
require 'rspec'
|
4
|
+
require 'active_record/connection_adapters/master_slave_adapter'
|
4
5
|
|
5
6
|
ActiveRecord::Base.logger =
|
6
|
-
Logger.new(
|
7
|
+
Logger.new($stdout).tap { |l| l.level = Logger::DEBUG }
|
7
8
|
|
8
|
-
|
9
|
+
module ActiveRecord
|
10
|
+
class Base
|
11
|
+
cattr_accessor :master_mock, :slave_mock
|
12
|
+
def self.test_connection(config)
|
13
|
+
config[:database] == 'slave' ? slave_mock : master_mock
|
14
|
+
end
|
9
15
|
|
10
|
-
|
16
|
+
def self.test_master_slave_connection(config)
|
17
|
+
TestMasterSlaveAdapter.new(config, logger)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module ConnectionAdapters
|
22
|
+
class TestMasterSlaveAdapter < MasterSlaveAdapter::Base
|
23
|
+
def master_clock
|
24
|
+
end
|
25
|
+
|
26
|
+
def slave_clock(connection)
|
27
|
+
end
|
11
28
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
29
|
+
def connection_error?(exception)
|
30
|
+
true
|
31
|
+
end
|
32
|
+
end
|
16
33
|
end
|
17
34
|
end
|
18
35
|
|
@@ -34,6 +51,7 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
|
|
34
51
|
{
|
35
52
|
:reconnect! => true,
|
36
53
|
:disconnect! => true,
|
54
|
+
:active? => true,
|
37
55
|
}
|
38
56
|
end
|
39
57
|
|
@@ -58,16 +76,10 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
|
|
58
76
|
ActiveRecord::Base.connection
|
59
77
|
end
|
60
78
|
|
61
|
-
SchemaStatements = ActiveRecord::ConnectionAdapters::SchemaStatements.
|
79
|
+
SchemaStatements = ActiveRecord::ConnectionAdapters::SchemaStatements.public_instance_methods.map(&:to_sym)
|
62
80
|
SelectMethods = [ :select_all, :select_one, :select_rows, :select_value, :select_values ]
|
63
|
-
Clock = ActiveRecord::ConnectionAdapters::MasterSlaveAdapter::Clock
|
64
81
|
|
65
82
|
before do
|
66
|
-
unless database_setup[:disable_connection_test] == 'true'
|
67
|
-
[ master_connection, slave_connection ].each do |c|
|
68
|
-
c.should_receive(:active?).exactly(2).times.and_return(true)
|
69
|
-
end
|
70
|
-
end
|
71
83
|
ActiveRecord::Base.establish_connection(database_setup)
|
72
84
|
end
|
73
85
|
|
@@ -76,12 +88,6 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
|
|
76
88
|
end
|
77
89
|
|
78
90
|
describe 'common configuration' do
|
79
|
-
before do
|
80
|
-
[ master_connection, slave_connection ].each do |c|
|
81
|
-
c.stub!( :select_value ).with( "SELECT 1", "test select" ).and_return( true )
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
91
|
it "should call 'columns' on master" do
|
86
92
|
master_connection.should_receive(:columns)
|
87
93
|
adapter_connection.columns
|
@@ -145,7 +151,7 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
|
|
145
151
|
end
|
146
152
|
|
147
153
|
it 'should be a master slave connection' do
|
148
|
-
adapter_connection.class.should == ActiveRecord::ConnectionAdapters::
|
154
|
+
adapter_connection.class.should == ActiveRecord::ConnectionAdapters::TestMasterSlaveAdapter
|
149
155
|
end
|
150
156
|
|
151
157
|
it 'should have a master connection' do
|
@@ -153,39 +159,36 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
|
|
153
159
|
end
|
154
160
|
|
155
161
|
it 'should have a slave connection' do
|
156
|
-
master_connection.stub!( :open_transactions ).and_return( 0 )
|
157
162
|
adapter_connection.slave_connection!.should == slave_connection
|
158
163
|
end
|
159
164
|
end
|
160
165
|
|
161
166
|
describe "connection testing" do
|
167
|
+
before do
|
168
|
+
master_connection.unstub(:active?)
|
169
|
+
slave_connection.unstub(:active?)
|
170
|
+
end
|
171
|
+
|
162
172
|
context "disabled" do
|
163
173
|
let(:database_setup) do
|
164
174
|
default_database_setup.merge(:disable_connection_test => 'true')
|
165
175
|
end
|
166
176
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
c.should_receive(method).with('testing').and_return(true)
|
173
|
-
end
|
174
|
-
adapter_connection.send(method, 'testing')
|
175
|
-
end
|
176
|
-
end
|
177
|
+
it "should not perform the testing" do
|
178
|
+
master_connection.should_not_receive(:active?)
|
179
|
+
slave_connection.should_not_receive(:active?)
|
180
|
+
|
181
|
+
adapter_connection.active?.should == true
|
177
182
|
end
|
183
|
+
end
|
178
184
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
adapter_connection.send(method, 'testing')
|
187
|
-
end
|
188
|
-
end
|
185
|
+
context "enabled" do
|
186
|
+
it "should perform the testing" do
|
187
|
+
# twice == one during connection + one on explicit #active? call
|
188
|
+
master_connection.should_receive(:active?).twice.and_return(true)
|
189
|
+
slave_connection.should_receive(:active?).twice.and_return(true)
|
190
|
+
|
191
|
+
adapter_connection.active?.should == true
|
189
192
|
end
|
190
193
|
end
|
191
194
|
end
|
@@ -196,259 +199,11 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
|
|
196
199
|
end
|
197
200
|
end
|
198
201
|
|
199
|
-
describe 'consistency' do
|
200
|
-
before do
|
201
|
-
ActiveRecord::ConnectionAdapters::MasterSlaveAdapter.reset!
|
202
|
-
|
203
|
-
[ master_connection, slave_connection ].each do |c|
|
204
|
-
c.stub!(:select_value).with("SELECT 1", "test select").and_return(true)
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
def zero
|
209
|
-
Clock.zero
|
210
|
-
end
|
211
|
-
|
212
|
-
def master_position(pos)
|
213
|
-
Clock.new('', pos)
|
214
|
-
end
|
215
|
-
|
216
|
-
def slave_should_report_clock(pos)
|
217
|
-
pos = Array(pos)
|
218
|
-
values = pos.map { |p| { 'Relay_Master_Log_File' => '', 'Exec_Master_Log_Pos' => p } }
|
219
|
-
slave_connection.
|
220
|
-
should_receive('select_one').exactly(pos.length).with('SHOW SLAVE STATUS').
|
221
|
-
and_return(*values)
|
222
|
-
end
|
223
|
-
|
224
|
-
def master_should_report_clock(pos)
|
225
|
-
pos = Array(pos)
|
226
|
-
values = pos.map { |p| { 'File' => '', 'Position' => p } }
|
227
|
-
master_connection.
|
228
|
-
should_receive('select_one').exactly(pos.length).with('SHOW MASTER STATUS').
|
229
|
-
and_return(*values)
|
230
|
-
end
|
231
|
-
|
232
|
-
SelectMethods.each do |method|
|
233
|
-
it "should raise an exception if consistency is nil" do
|
234
|
-
lambda do
|
235
|
-
ActiveRecord::Base.with_consistency(nil) do
|
236
|
-
end
|
237
|
-
end.should raise_error(ArgumentError)
|
238
|
-
end
|
239
|
-
|
240
|
-
it "should send the method '#{method}' to the slave if clock.zero is given" do
|
241
|
-
slave_should_report_clock(0)
|
242
|
-
slave_connection.should_receive(method).with('testing').and_return(true)
|
243
|
-
old_clock = zero
|
244
|
-
new_clock = ActiveRecord::Base.with_consistency(old_clock) do
|
245
|
-
adapter_connection.send(method, 'testing')
|
246
|
-
end
|
247
|
-
new_clock.should be_a(zero.class)
|
248
|
-
new_clock.should equal(zero)
|
249
|
-
end
|
250
|
-
|
251
|
-
it "should send the method '#{method}' to the master if slave hasn't cought up to required clock yet" do
|
252
|
-
slave_should_report_clock(0)
|
253
|
-
master_connection.should_receive(method).with('testing').and_return(true)
|
254
|
-
old_clock = master_position(1)
|
255
|
-
new_clock = ActiveRecord::Base.with_consistency(old_clock) do
|
256
|
-
adapter_connection.send(method, 'testing' )
|
257
|
-
end
|
258
|
-
new_clock.should be_a(zero.class)
|
259
|
-
new_clock.should equal(old_clock)
|
260
|
-
end
|
261
|
-
|
262
|
-
it "should send the method '#{method}' to the master connection if there are open transactions" do
|
263
|
-
master_connection.stub!(:open_transactions).and_return(1)
|
264
|
-
master_connection.should_receive(method).with('testing').and_return(true)
|
265
|
-
old_clock = zero
|
266
|
-
new_clock = ActiveRecord::Base.with_consistency(old_clock) do
|
267
|
-
adapter_connection.send(method, 'testing')
|
268
|
-
end
|
269
|
-
new_clock.should be_a(zero.class)
|
270
|
-
new_clock.should equal(zero)
|
271
|
-
end
|
272
|
-
|
273
|
-
it "should send the method '#{method}' to the master after a write operation" do
|
274
|
-
slave_should_report_clock(0)
|
275
|
-
master_should_report_clock(2)
|
276
|
-
slave_connection.should_receive(method).with('testing').and_return(true)
|
277
|
-
master_connection.should_receive('update').with('testing').and_return(true)
|
278
|
-
master_connection.should_receive(method).with('testing').and_return(true)
|
279
|
-
old_clock = zero
|
280
|
-
new_clock = ActiveRecord::Base.with_consistency(old_clock) do
|
281
|
-
adapter_connection.send(method, 'testing') # slave
|
282
|
-
adapter_connection.send('update', 'testing') # master
|
283
|
-
adapter_connection.send(method, 'testing') # master
|
284
|
-
end
|
285
|
-
new_clock.should be_a(zero.class)
|
286
|
-
new_clock.should > old_clock
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
it "should update the clock after a transaction" do
|
291
|
-
slave_should_report_clock(0)
|
292
|
-
master_should_report_clock([0, 1, 1])
|
293
|
-
|
294
|
-
slave_connection.
|
295
|
-
should_receive('select_all').exactly(1).times.with('testing').
|
296
|
-
and_return(true)
|
297
|
-
|
298
|
-
master_connection.
|
299
|
-
should_receive('update').exactly(3).times.with('testing').
|
300
|
-
and_return(true)
|
301
|
-
master_connection.
|
302
|
-
should_receive('select_all').exactly(5).times.with('testing').
|
303
|
-
and_return(true)
|
304
|
-
%w(begin_db_transaction
|
305
|
-
commit_db_transaction
|
306
|
-
increment_open_transactions
|
307
|
-
decrement_open_transactions
|
308
|
-
outside_transaction?).each do |txstmt|
|
309
|
-
master_connection.should_receive(txstmt).exactly(1).times
|
310
|
-
end
|
311
|
-
|
312
|
-
master_connection.
|
313
|
-
should_receive('open_transactions').exactly(13).times.
|
314
|
-
and_return(
|
315
|
-
# adapter: with_consistency, select_all, update, select_all
|
316
|
-
0, 0, 0, 0,
|
317
|
-
# connection: transaction
|
318
|
-
0,
|
319
|
-
# adapter: select_all, update, select_all, commit_db_transaction
|
320
|
-
1, 1, 1, 0,
|
321
|
-
# connection: transaction (ensure)
|
322
|
-
0,
|
323
|
-
# adapter: select_all, update, select_all
|
324
|
-
0, 0, 0
|
325
|
-
)
|
326
|
-
|
327
|
-
old_clock = zero
|
328
|
-
new_clock = ActiveRecord::Base.with_consistency(old_clock) do
|
329
|
-
adapter_connection.send('select_all', 'testing') # slave s=0 m=0
|
330
|
-
adapter_connection.send('update', 'testing') # master s=0 m=1
|
331
|
-
adapter_connection.send('select_all', 'testing') # master s=0 m=1
|
332
|
-
|
333
|
-
ActiveRecord::Base.transaction do
|
334
|
-
adapter_connection.send('select_all', 'testing') # master s=0 m=1
|
335
|
-
adapter_connection.send('update', 'testing') # master s=0 m=1
|
336
|
-
adapter_connection.send('select_all', 'testing') # master s=0 m=1
|
337
|
-
end
|
338
|
-
|
339
|
-
adapter_connection.send('select_all', 'testing') # master s=0 m=2
|
340
|
-
adapter_connection.send('update', 'testing') # master s=0 m=3
|
341
|
-
adapter_connection.send('select_all', 'testing') # master s=0 m=3
|
342
|
-
end
|
343
|
-
|
344
|
-
new_clock.should > old_clock
|
345
|
-
end
|
346
|
-
|
347
|
-
context "with nested with_consistency" do
|
348
|
-
it "should return the same clock if not writing and no lag" do
|
349
|
-
slave_should_report_clock(0) # note: tests memoizing slave clock
|
350
|
-
slave_connection.
|
351
|
-
should_receive('select_one').exactly(3).times.with('testing').
|
352
|
-
and_return(true)
|
353
|
-
|
354
|
-
old_clock = zero
|
355
|
-
new_clock = ActiveRecord::Base.with_consistency(old_clock) do
|
356
|
-
adapter_connection.send('select_one', 'testing')
|
357
|
-
ActiveRecord::Base.with_consistency(old_clock) do
|
358
|
-
adapter_connection.send('select_one', 'testing')
|
359
|
-
end
|
360
|
-
adapter_connection.send('select_one', 'testing')
|
361
|
-
end
|
362
|
-
new_clock.should equal(old_clock)
|
363
|
-
end
|
364
|
-
|
365
|
-
it "requesting a newer clock should return a new clock" do
|
366
|
-
adapter_connection.
|
367
|
-
should_receive('slave_consistent?').exactly(2).times.
|
368
|
-
and_return(true, false)
|
369
|
-
slave_connection.
|
370
|
-
should_receive('select_all').exactly(2).times.with('testing').
|
371
|
-
and_return(true)
|
372
|
-
master_connection.
|
373
|
-
should_receive('select_all').exactly(1).times.with('testing').
|
374
|
-
and_return(true)
|
375
|
-
|
376
|
-
start_clock = zero
|
377
|
-
inner_clock = zero
|
378
|
-
outer_clock = ActiveRecord::Base.with_consistency(start_clock) do
|
379
|
-
adapter_connection.send('select_all', 'testing') # slave
|
380
|
-
inner_clock = ActiveRecord::Base.with_consistency(master_position(1)) do
|
381
|
-
adapter_connection.send('select_all', 'testing') # master
|
382
|
-
end
|
383
|
-
adapter_connection.send('select_all', 'testing') # slave
|
384
|
-
end
|
385
|
-
|
386
|
-
start_clock.should equal(outer_clock)
|
387
|
-
inner_clock.should > start_clock
|
388
|
-
end
|
389
|
-
end
|
390
|
-
|
391
|
-
it "should do the right thing when nested inside with_master" do
|
392
|
-
slave_should_report_clock(0)
|
393
|
-
slave_connection.should_receive('select_all').exactly(1).times.with('testing').and_return(true)
|
394
|
-
master_connection.should_receive('select_all').exactly(2).times.with('testing').and_return(true)
|
395
|
-
ActiveRecord::Base.with_master do
|
396
|
-
adapter_connection.send('select_all', 'testing') # master
|
397
|
-
ActiveRecord::Base.with_consistency(zero) do
|
398
|
-
adapter_connection.send('select_all', 'testing') # slave
|
399
|
-
end
|
400
|
-
adapter_connection.send('select_all', 'testing') # master
|
401
|
-
end
|
402
|
-
end
|
403
|
-
|
404
|
-
it "should do the right thing when nested inside with_slave" do
|
405
|
-
slave_should_report_clock(0)
|
406
|
-
slave_connection.should_receive('select_all').exactly(3).times.with('testing').and_return(true)
|
407
|
-
ActiveRecord::Base.with_slave do
|
408
|
-
adapter_connection.send('select_all', 'testing') # slave
|
409
|
-
ActiveRecord::Base.with_consistency(zero) do
|
410
|
-
adapter_connection.send('select_all', 'testing') # slave
|
411
|
-
end
|
412
|
-
adapter_connection.send('select_all', 'testing') # slave
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
it "should do the right thing when wrapping with_master" do
|
417
|
-
slave_should_report_clock(0)
|
418
|
-
slave_connection.should_receive('select_all').exactly(2).times.with('testing').and_return(true)
|
419
|
-
master_connection.should_receive('select_all').exactly(1).times.with('testing').and_return(true)
|
420
|
-
ActiveRecord::Base.with_consistency(zero) do
|
421
|
-
adapter_connection.send('select_all', 'testing') # slave
|
422
|
-
ActiveRecord::Base.with_master do
|
423
|
-
adapter_connection.send('select_all', 'testing') # master
|
424
|
-
end
|
425
|
-
adapter_connection.send('select_all', 'testing') # slave
|
426
|
-
end
|
427
|
-
end
|
428
|
-
|
429
|
-
it "should do the right thing when wrapping with_slave" do
|
430
|
-
slave_should_report_clock(0)
|
431
|
-
slave_connection.should_receive('select_all').exactly(1).times.with('testing').and_return(true)
|
432
|
-
master_connection.should_receive('select_all').exactly(2).times.with('testing').and_return(true)
|
433
|
-
ActiveRecord::Base.with_consistency(master_position(1)) do
|
434
|
-
adapter_connection.send('select_all', 'testing') # master
|
435
|
-
ActiveRecord::Base.with_slave do
|
436
|
-
adapter_connection.send('select_all', 'testing') # slave
|
437
|
-
end
|
438
|
-
adapter_connection.send('select_all', 'testing') # master
|
439
|
-
end
|
440
|
-
end
|
441
|
-
end # /with_consistency
|
442
|
-
|
443
202
|
describe "transaction callbacks" do
|
444
|
-
before do
|
445
|
-
ActiveRecord::ConnectionAdapters::MasterSlaveAdapter.reset!
|
446
|
-
end
|
447
|
-
|
448
203
|
def run_tx
|
449
204
|
adapter_connection.
|
450
205
|
should_receive('master_clock').
|
451
|
-
and_return(
|
206
|
+
and_return(1)
|
452
207
|
%w(begin_db_transaction
|
453
208
|
commit_db_transaction
|
454
209
|
increment_open_transactions
|