master_slave_adapter 1.0.0.beta2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -31,7 +31,7 @@ task :spec => ['spec:common', 'spec:integration']
31
31
  namespace :spec do
32
32
  desc 'Run common specs'
33
33
  MasterSlaveAdapterRSpecTask.new(:common) do |task|
34
- task.pattern = './spec/*_spec.rb'
34
+ task.pattern = './spec/common/*_spec.rb'
35
35
  task.exclude = /mysql2/ unless mysql2_adapter_available?
36
36
  task.verbose = false
37
37
  end
data/Readme.md CHANGED
@@ -180,6 +180,16 @@ development:
180
180
  - host: slave02
181
181
  ```
182
182
 
183
+ ## Testing
184
+
185
+ You can execute all tests against your current ruby version via:
186
+
187
+ rake spec
188
+
189
+ In case you have `rvm` installed, you can test against 1.8.7, 1.9.2 and 1.9.3 as well as ActiveRecord 2 and 3 via:
190
+
191
+ bash spec/all.sh
192
+
183
193
  ## Credits
184
194
 
185
195
  * Maurício Lenhares - _original master_slave_adapter plugin_
@@ -1,7 +1,7 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module MasterSlaveAdapter
4
- VERSION = "1.0.0.beta2"
4
+ VERSION = "1.0.0"
5
5
  end
6
6
  end
7
7
  end
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.version = ActiveRecord::ConnectionAdapters::MasterSlaveAdapter::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
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}
10
+ s.email = %q{tiago@soundcloud.com ts@soundcloud.com}
11
11
  s.homepage = 'http://github.com/soundcloud/master_slave_adapter'
12
12
  s.summary = %q{Replication Aware Master/Slave Database Adapter for ActiveRecord}
13
13
  s.description = %q{(MySQL) Replication Aware Master/Slave Database Adapter for ActiveRecord}
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.required_ruby_version = '>= 1.8.7'
21
21
  s.required_rubygems_version = '>= 1.3.7'
22
22
 
23
- s.add_dependency 'activerecord', ['>= 2.3.9', '<= 4.0']
23
+ s.add_dependency 'activerecord', ['>= 2.3.9', '< 4.0']
24
24
 
25
25
  s.add_development_dependency 'rake'
26
26
  s.add_development_dependency 'rspec'
data/spec/all.sh CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
- source ~/.rvm/scripts/rvm
3
+ source `which rvm | sed 's/rvm\/bin/rvm\/scripts/'`
4
4
 
5
5
  for ruby in 1.8.7 1.9.2 1.9.3; do
6
6
  rvm use $ruby
@@ -1,4 +1,4 @@
1
- $: << File.expand_path(File.join(File.dirname( __FILE__ ), '..', 'lib'))
1
+ $: << File.expand_path(File.join(File.dirname( __FILE__ ), '..', '..', 'lib'))
2
2
 
3
3
  require 'rspec'
4
4
  require 'active_record/connection_adapters/master_slave_adapter/circuit_breaker'
@@ -1,12 +1,12 @@
1
- $: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
1
+ $: << File.expand_path(File.join(File.dirname( __FILE__ ), '..', '..', 'lib'))
2
2
 
3
3
  require 'rspec'
4
- require 'logger'
5
- require 'active_record/connection_adapters/master_slave_adapter'
4
+ require 'common/support/connection_setup_helper'
6
5
 
7
6
  module ActiveRecord
8
7
  class Base
9
8
  cattr_accessor :master_mock, :slave_mock
9
+
10
10
  def self.test_connection(config)
11
11
  config[:database] == 'slave' ? slave_mock : master_mock
12
12
  end
@@ -27,65 +27,14 @@ module ActiveRecord
27
27
  end
28
28
 
29
29
  def connection_error?(exception)
30
- true
31
30
  end
32
31
  end
33
32
  end
34
33
  end
35
34
 
36
35
  describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
37
- let(:default_database_setup) do
38
- {
39
- :adapter => 'master_slave',
40
- :username => 'root',
41
- :database => 'slave',
42
- :connection_adapter => 'test',
43
- :master => { :username => 'root', :database => 'master' },
44
- :slaves => [{ :database => 'slave' }],
45
- }
46
- end
47
-
48
- let(:database_setup) { default_database_setup }
49
-
50
- let(:mocked_methods) do
51
- {
52
- :reconnect! => true,
53
- :disconnect! => true,
54
- :active? => true,
55
- }
56
- end
57
-
58
- let!(:master_connection) do
59
- mock(
60
- 'master connection',
61
- mocked_methods.merge(:open_transactions => 0)
62
- ).tap do |conn|
63
- conn.stub!(:uncached).and_yield
64
- ActiveRecord::Base.master_mock = conn
65
- end
66
- end
67
-
68
- let!(:slave_connection) do
69
- mock('slave connection', mocked_methods).tap do |conn|
70
- conn.stub!(:uncached).and_yield
71
- ActiveRecord::Base.slave_mock = conn
72
- end
73
- end
74
-
75
- def adapter_connection
76
- ActiveRecord::Base.connection
77
- end
78
-
79
- SchemaStatements = ActiveRecord::ConnectionAdapters::SchemaStatements.public_instance_methods.map(&:to_sym)
80
- SelectMethods = [ :select_all, :select_one, :select_rows, :select_value, :select_values ] unless defined?(SelectMethods)
81
-
82
- before do
83
- ActiveRecord::Base.establish_connection(database_setup)
84
- end
85
-
86
- after do
87
- ActiveRecord::Base.connection_handler.clear_all_connections!
88
- end
36
+ include_context 'connection setup'
37
+ let(:connection_adapter) { 'test' }
89
38
 
90
39
  describe 'common configuration' do
91
40
  it "should call 'columns' on master" do
@@ -132,8 +81,8 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
132
81
  end
133
82
 
134
83
  it "raises MasterUnavailable if master is not available" do
84
+ adapter_connection.stub(:connection_error?).and_return(true)
135
85
  master_connection.stub(:open_transactions).and_return(1)
136
- master_connection.stub(:connection_error?).and_return(true)
137
86
  master_connection.should_receive(method).with('testing').and_raise(ActiveRecord::StatementInvalid)
138
87
 
139
88
  expect do
@@ -150,7 +99,7 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
150
99
  end
151
100
 
152
101
  it "should raise MasterSlaveAdapter if master is not available" do
153
- master_connection.stub(:connection_error?).and_return(true)
102
+ adapter_connection.stub(:connection_error?).and_return(true)
154
103
  master_connection.should_receive(method).and_raise(ActiveRecord::StatementInvalid)
155
104
 
156
105
  expect do
@@ -0,0 +1,68 @@
1
+ $: << File.expand_path(File.join(File.dirname( __FILE__ ), '..', '..', 'lib'))
2
+
3
+ require 'rspec'
4
+ require 'common/support/connection_setup_helper'
5
+ require 'common/support/mysql_consistency_examples'
6
+ require 'active_record/connection_adapters/mysql2_master_slave_adapter'
7
+
8
+ module ActiveRecord
9
+ class Base
10
+ cattr_accessor :master_mock, :slave_mock
11
+
12
+ def self.mysql2_connection(config)
13
+ config[:database] == 'slave' ? slave_mock : master_mock
14
+ end
15
+ end
16
+ end
17
+
18
+ describe ActiveRecord::ConnectionAdapters::Mysql2MasterSlaveAdapter do
19
+ include_context 'connection setup'
20
+ let(:connection_adapter) { 'mysql2' }
21
+
22
+ it_should_behave_like 'mysql consistency'
23
+
24
+ describe "connection error detection" do
25
+ {
26
+ 2002 => "query: not connected",
27
+ 2003 => "Can't connect to MySQL server on 'localhost' (3306)",
28
+ 2006 => "MySQL server has gone away",
29
+ 2013 => "Lost connection to MySQL server during query",
30
+ }.each do |errno, description|
31
+ it "raises MasterUnavailable for '#{description}' during query execution" do
32
+ master_connection.stub_chain(:raw_connection, :errno).and_return(errno)
33
+ master_connection.should_receive(:insert).and_raise(ActiveRecord::StatementInvalid.new("Mysql2::Error: #{description}: INSERT 42"))
34
+
35
+ expect do
36
+ adapter_connection.insert("INSERT 42")
37
+ end.to raise_error(ActiveRecord::MasterUnavailable)
38
+ end
39
+
40
+ it "doesn't raise anything for '#{description}' during connection" do
41
+ error = Mysql2::Error.new(description)
42
+ error.stub(:errno).and_return(errno)
43
+ ActiveRecord::Base.should_receive(:master_mock).and_raise(error)
44
+
45
+ expect do
46
+ ActiveRecord::Base.connection_handler.clear_all_connections!
47
+ ActiveRecord::Base.connection
48
+ end.to_not raise_error
49
+ end
50
+ end
51
+
52
+ it "raises MasterUnavailable for 'closed MySQL connection' during query execution" do
53
+ master_connection.should_receive(:insert).and_raise(ActiveRecord::StatementInvalid.new("Mysql2::Error: closed MySQL connection: INSERT 42"))
54
+
55
+ expect do
56
+ adapter_connection.insert("INSERT 42")
57
+ end.to raise_error(ActiveRecord::MasterUnavailable)
58
+ end
59
+
60
+ it "raises StatementInvalid for other errors" do
61
+ master_connection.should_receive(:insert).and_raise(ActiveRecord::StatementInvalid.new("Mysql2::Error: Query execution was interrupted: INSERT 42"))
62
+
63
+ expect do
64
+ adapter_connection.insert("INSERT 42")
65
+ end.to raise_error(ActiveRecord::StatementInvalid)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,62 @@
1
+ $: << File.expand_path(File.join(File.dirname( __FILE__ ), '..', '..', 'lib'))
2
+
3
+ require 'rspec'
4
+ require 'common/support/connection_setup_helper'
5
+ require 'common/support/mysql_consistency_examples'
6
+ require 'active_record/connection_adapters/mysql_master_slave_adapter'
7
+
8
+ module ActiveRecord
9
+ class Base
10
+ cattr_accessor :master_mock, :slave_mock
11
+
12
+ def self.mysql_connection(config)
13
+ config[:database] == 'slave' ? slave_mock : master_mock
14
+ end
15
+ end
16
+ end
17
+
18
+ describe ActiveRecord::ConnectionAdapters::MysqlMasterSlaveAdapter do
19
+ include_context 'connection setup'
20
+ let(:connection_adapter) { 'mysql' }
21
+
22
+ it_should_behave_like 'mysql consistency'
23
+
24
+ describe "connection error detection" do
25
+ {
26
+ Mysql::Error::CR_CONNECTION_ERROR => "query: not connected",
27
+ Mysql::Error::CR_CONN_HOST_ERROR => "Can't connect to MySQL server on 'localhost' (3306)",
28
+ Mysql::Error::CR_SERVER_GONE_ERROR => "MySQL server has gone away",
29
+ Mysql::Error::CR_SERVER_LOST => "Lost connection to MySQL server during query",
30
+ }.each do |errno, description|
31
+ it "raises MasterUnavailable for '#{description}' during query execution" do
32
+ master_connection.stub_chain(:raw_connection, :errno).and_return(errno)
33
+ master_connection.should_receive(:insert).and_raise(ActiveRecord::StatementInvalid.new("Mysql::Error: #{description}: INSERT 42"))
34
+
35
+ expect do
36
+ adapter_connection.insert("INSERT 42")
37
+ end.to raise_error(ActiveRecord::MasterUnavailable)
38
+ end
39
+
40
+ it "doesn't raise anything for '#{description}' during connection" do
41
+ error = Mysql::Error.new(description)
42
+ error.stub(:errno).and_return(errno)
43
+ ActiveRecord::Base.should_receive(:master_mock).and_raise(error)
44
+
45
+ expect do
46
+ ActiveRecord::Base.connection_handler.clear_all_connections!
47
+ ActiveRecord::Base.connection
48
+ end.to_not raise_error
49
+ end
50
+ end
51
+
52
+ it "raises StatementInvalid for other errors" do
53
+ error = ActiveRecord::StatementInvalid.new("Mysql::Error: Query execution was interrupted: INSERT 42")
54
+ master_connection.stub_chain(:raw_connection, :errno).and_return(Mysql::Error::ER_QUERY_INTERRUPTED)
55
+ master_connection.should_receive(:insert).and_raise(error)
56
+
57
+ expect do
58
+ adapter_connection.insert("INSERT 42")
59
+ end.to raise_error(ActiveRecord::StatementInvalid)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,56 @@
1
+ require 'active_record/connection_adapters/master_slave_adapter'
2
+
3
+ SchemaStatements = ActiveRecord::ConnectionAdapters::SchemaStatements.public_instance_methods.map(&:to_sym)
4
+ SelectMethods = [ :select_all, :select_one, :select_rows, :select_value, :select_values ]
5
+
6
+ shared_context 'connection setup' do
7
+ let(:default_database_setup) do
8
+ {
9
+ :adapter => 'master_slave',
10
+ :username => 'root',
11
+ :database => 'slave',
12
+ :connection_adapter => connection_adapter,
13
+ :master => { :username => 'root', :database => 'master' },
14
+ :slaves => [{ :database => 'slave' }],
15
+ }
16
+ end
17
+
18
+ let(:database_setup) do
19
+ default_database_setup
20
+ end
21
+
22
+ let(:mocked_methods) do
23
+ {
24
+ :reconnect! => true,
25
+ :disconnect! => true,
26
+ :active? => true,
27
+ }
28
+ end
29
+
30
+ let(:master_connection) do
31
+ stubs = mocked_methods.merge(:open_transactions => 0)
32
+ mock('master connection', stubs).tap do |conn|
33
+ conn.stub(:uncached).and_yield
34
+ end
35
+ end
36
+
37
+ let(:slave_connection) do
38
+ mock('slave connection', mocked_methods).tap do |conn|
39
+ conn.stub(:uncached).and_yield
40
+ end
41
+ end
42
+
43
+ before do
44
+ ActiveRecord::Base.master_mock = master_connection
45
+ ActiveRecord::Base.slave_mock = slave_connection
46
+ ActiveRecord::Base.establish_connection(database_setup)
47
+ end
48
+
49
+ after do
50
+ ActiveRecord::Base.connection_handler.clear_all_connections!
51
+ end
52
+
53
+ def adapter_connection
54
+ ActiveRecord::Base.connection
55
+ end
56
+ end
@@ -0,0 +1,263 @@
1
+ require 'active_record/connection_adapters/master_slave_adapter/clock'
2
+
3
+ Clock = ActiveRecord::ConnectionAdapters::MasterSlaveAdapter::Clock
4
+
5
+ shared_examples_for 'mysql consistency' do
6
+ def zero
7
+ Clock.zero
8
+ end
9
+
10
+ def master_position(pos)
11
+ Clock.new('', pos)
12
+ end
13
+
14
+ def supports_prepared_statements?
15
+ described_class == ActiveRecord::ConnectionAdapters::MysqlMasterSlaveAdapter &&
16
+ ActiveRecord::ConnectionAdapters::MysqlAdapter.instance_methods.map(&:to_sym).include?(:exec_without_stmt)
17
+ end
18
+
19
+ def select_method
20
+ supports_prepared_statements? ? :exec_without_stmt : :select_one
21
+ end
22
+
23
+ def should_report_clock(pos, connection, log_file, log_pos, sql)
24
+ pos = Array(pos)
25
+ values = pos.map { |p| { log_file => '', log_pos => p } }
26
+ values.map! { |result| [ result ] } if supports_prepared_statements?
27
+
28
+ connection.
29
+ should_receive(select_method).exactly(pos.length).times.
30
+ with(sql).
31
+ and_return(*values)
32
+ end
33
+
34
+ def slave_should_report_clock(pos)
35
+ should_report_clock(pos, slave_connection, 'Relay_Master_Log_File', 'Exec_Master_Log_Pos', 'SHOW SLAVE STATUS')
36
+ end
37
+
38
+ def master_should_report_clock(pos)
39
+ should_report_clock(pos, master_connection, 'File', 'Position', 'SHOW MASTER STATUS')
40
+ end
41
+
42
+ SelectMethods.each do |method|
43
+ it "should send the method '#{method}' to the slave if nil is given" do
44
+ slave_should_report_clock(0)
45
+ slave_connection.should_receive(method).with('testing').and_return(true)
46
+ new_clock = ActiveRecord::Base.with_consistency(nil) do
47
+ adapter_connection.send(method, 'testing')
48
+ end
49
+ new_clock.should be_a(Clock)
50
+ new_clock.should equal(zero)
51
+ end
52
+
53
+ it "should send the method '#{method}' to the slave if clock.zero is given" do
54
+ slave_should_report_clock(0)
55
+ slave_connection.should_receive(method).with('testing').and_return(true)
56
+ old_clock = zero
57
+ new_clock = ActiveRecord::Base.with_consistency(old_clock) do
58
+ adapter_connection.send(method, 'testing')
59
+ end
60
+ new_clock.should be_a(Clock)
61
+ new_clock.should equal(old_clock)
62
+ end
63
+
64
+ it "should send the method '#{method}' to the master if slave hasn't cought up to required clock yet" do
65
+ slave_should_report_clock(0)
66
+ master_connection.should_receive(method).with('testing').and_return(true)
67
+ old_clock = master_position(1)
68
+ new_clock = ActiveRecord::Base.with_consistency(old_clock) do
69
+ adapter_connection.send(method, 'testing' )
70
+ end
71
+ new_clock.should be_a(Clock)
72
+ new_clock.should equal(old_clock)
73
+ end
74
+
75
+ it "should send the method '#{method}' to the master connection if there are open transactions" do
76
+ master_connection.stub!(:open_transactions).and_return(1)
77
+ master_connection.should_receive(method).with('testing').and_return(true)
78
+ old_clock = zero
79
+ new_clock = ActiveRecord::Base.with_consistency(old_clock) do
80
+ adapter_connection.send(method, 'testing')
81
+ end
82
+ new_clock.should be_a(Clock)
83
+ new_clock.should equal(zero)
84
+ end
85
+
86
+ it "should send the method '#{method}' to the master after a write operation" do
87
+ slave_should_report_clock(0)
88
+ master_should_report_clock(2)
89
+ slave_connection.should_receive(method).with('testing').and_return(true)
90
+ master_connection.should_receive(:update).with('testing').and_return(true)
91
+ master_connection.should_receive(method).with('testing').and_return(true)
92
+ old_clock = zero
93
+ new_clock = ActiveRecord::Base.with_consistency(old_clock) do
94
+ adapter_connection.send(method, 'testing') # slave
95
+ adapter_connection.send(:update, 'testing') # master
96
+ adapter_connection.send(method, 'testing') # master
97
+ end
98
+ new_clock.should be_a(Clock)
99
+ new_clock.should > old_clock
100
+ end
101
+ end
102
+
103
+ it "should update the clock after a transaction" do
104
+ slave_should_report_clock(0)
105
+ master_should_report_clock([0, 1, 1])
106
+
107
+ slave_connection.
108
+ should_receive(:select_all).exactly(1).times.with('testing').
109
+ and_return(true)
110
+
111
+ master_connection.
112
+ should_receive(:update).exactly(3).times.with('testing').
113
+ and_return(true)
114
+ master_connection.
115
+ should_receive(:select_all).exactly(5).times.with('testing').
116
+ and_return(true)
117
+ %w(begin_db_transaction
118
+ commit_db_transaction
119
+ increment_open_transactions
120
+ decrement_open_transactions
121
+ outside_transaction?).each do |txstmt|
122
+ master_connection.should_receive(txstmt).exactly(1).times
123
+ end
124
+
125
+ master_connection.
126
+ should_receive('open_transactions').exactly(13).times.
127
+ and_return(
128
+ # adapter: with_consistency, select_all, update, select_all
129
+ 0, 0, 0, 0,
130
+ # connection: transaction
131
+ 0,
132
+ # adapter: select_all, update, select_all, commit_db_transaction
133
+ 1, 1, 1, 0,
134
+ # connection: transaction (ensure)
135
+ 0,
136
+ # adapter: select_all, update, select_all
137
+ 0, 0, 0
138
+ )
139
+
140
+ old_clock = zero
141
+ new_clock = ActiveRecord::Base.with_consistency(old_clock) do
142
+ adapter_connection.send(:select_all, 'testing') # slave s=0 m=0
143
+ adapter_connection.send(:update, 'testing') # master s=0 m=1
144
+ adapter_connection.send(:select_all, 'testing') # master s=0 m=1
145
+
146
+ ActiveRecord::Base.transaction do
147
+ adapter_connection.send(:select_all, 'testing') # master s=0 m=1
148
+ adapter_connection.send(:update, 'testing') # master s=0 m=1
149
+ adapter_connection.send(:select_all, 'testing') # master s=0 m=1
150
+ end
151
+
152
+ adapter_connection.send(:select_all, 'testing') # master s=0 m=2
153
+ adapter_connection.send(:update, 'testing') # master s=0 m=3
154
+ adapter_connection.send(:select_all, 'testing') # master s=0 m=3
155
+ end
156
+
157
+ new_clock.should > old_clock
158
+ end
159
+
160
+ context "with nested with_consistency" do
161
+ it "should return the same clock if not writing and no lag" do
162
+ slave_should_report_clock(0)
163
+ slave_connection.
164
+ should_receive(:select_one).exactly(3).times.with('testing').
165
+ and_return(true)
166
+
167
+ old_clock = zero
168
+ new_clock = ActiveRecord::Base.with_consistency(old_clock) do
169
+ adapter_connection.send(:select_one, 'testing')
170
+ ActiveRecord::Base.with_consistency(old_clock) do
171
+ adapter_connection.send(:select_one, 'testing')
172
+ end
173
+ adapter_connection.send(:select_one, 'testing')
174
+ end
175
+ new_clock.should equal(old_clock)
176
+ end
177
+
178
+ it "requesting a newer clock should return a new clock" do
179
+ adapter_connection.
180
+ should_receive('slave_consistent?').exactly(2).times.
181
+ and_return(true, false)
182
+ slave_connection.
183
+ should_receive(:select_all).exactly(2).times.with('testing').
184
+ and_return(true)
185
+ master_connection.
186
+ should_receive(:select_all).exactly(1).times.with('testing').
187
+ and_return(true)
188
+
189
+ start_clock = zero
190
+ inner_clock = zero
191
+ outer_clock = ActiveRecord::Base.with_consistency(start_clock) do
192
+ adapter_connection.send(:select_all, 'testing') # slave
193
+ inner_clock = ActiveRecord::Base.with_consistency(master_position(1)) do
194
+ adapter_connection.send(:select_all, 'testing') # master
195
+ end
196
+ adapter_connection.send(:select_all, 'testing') # slave
197
+ end
198
+
199
+ start_clock.should equal(outer_clock)
200
+ inner_clock.should > start_clock
201
+ end
202
+ end
203
+
204
+ it "should do the right thing when nested inside with_master" do
205
+ slave_should_report_clock(0)
206
+ slave_connection.should_receive(:select_all).exactly(1).times.with('testing').and_return(true)
207
+ master_connection.should_receive(:select_all).exactly(2).times.with('testing').and_return(true)
208
+ ActiveRecord::Base.with_master do
209
+ adapter_connection.send(:select_all, 'testing') # master
210
+ ActiveRecord::Base.with_consistency(zero) do
211
+ adapter_connection.send(:select_all, 'testing') # slave
212
+ end
213
+ adapter_connection.send(:select_all, 'testing') # master
214
+ end
215
+ end
216
+
217
+ it "should do the right thing when nested inside with_slave" do
218
+ slave_should_report_clock(0)
219
+ slave_connection.should_receive(:select_all).exactly(3).times.with('testing').and_return(true)
220
+ ActiveRecord::Base.with_slave do
221
+ adapter_connection.send(:select_all, 'testing') # slave
222
+ ActiveRecord::Base.with_consistency(zero) do
223
+ adapter_connection.send(:select_all, 'testing') # slave
224
+ end
225
+ adapter_connection.send(:select_all, 'testing') # slave
226
+ end
227
+ end
228
+
229
+ it "should do the right thing when wrapping with_master" do
230
+ slave_should_report_clock(0)
231
+ slave_connection.should_receive(:select_all).exactly(2).times.with('testing').and_return(true)
232
+ master_connection.should_receive(:select_all).exactly(1).times.with('testing').and_return(true)
233
+ ActiveRecord::Base.with_consistency(zero) do
234
+ adapter_connection.send(:select_all, 'testing') # slave
235
+ ActiveRecord::Base.with_master do
236
+ adapter_connection.send(:select_all, 'testing') # master
237
+ end
238
+ adapter_connection.send(:select_all, 'testing') # slave
239
+ end
240
+ end
241
+
242
+ it "should do the right thing when wrapping with_slave" do
243
+ slave_should_report_clock(0)
244
+ slave_connection.should_receive(:select_all).exactly(1).times.with('testing').and_return(true)
245
+ master_connection.should_receive(:select_all).exactly(2).times.with('testing').and_return(true)
246
+ ActiveRecord::Base.with_consistency(master_position(1)) do
247
+ adapter_connection.send(:select_all, 'testing') # master
248
+ ActiveRecord::Base.with_slave do
249
+ adapter_connection.send(:select_all, 'testing') # slave
250
+ end
251
+ adapter_connection.send(:select_all, 'testing') # master
252
+ end
253
+ end
254
+
255
+ it "should accept clock as string" do
256
+ slave_should_report_clock(0)
257
+ slave_connection.should_receive(:select_all).with('testing')
258
+
259
+ ActiveRecord::Base.with_consistency("@0") do
260
+ adapter_connection.send(:select_all, 'testing')
261
+ end
262
+ end
263
+ end
@@ -2,7 +2,7 @@ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
2
2
 
3
3
  require 'rspec'
4
4
  require 'master_slave_adapter'
5
- require 'integration/helpers/shared_mysql_examples'
5
+ require 'integration/support/shared_mysql_examples'
6
6
 
7
7
  describe "ActiveRecord::ConnectionAdapters::Mysql2MasterSlaveAdapter" do
8
8
  let(:connection_adapter) { 'mysql2' }
@@ -2,7 +2,7 @@ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
2
2
 
3
3
  require 'rspec'
4
4
  require 'master_slave_adapter'
5
- require 'integration/helpers/shared_mysql_examples'
5
+ require 'integration/support/shared_mysql_examples'
6
6
 
7
7
  describe "ActiveRecord::ConnectionAdapters::MysqlMasterSlaveAdapter" do
8
8
  let(:connection_adapter) { 'mysql' }
@@ -1,7 +1,7 @@
1
1
  require 'fileutils'
2
2
  require 'timeout'
3
3
 
4
- module MysqlHelper
4
+ module MysqlSetupHelper
5
5
  MASTER_ID = "1"
6
6
  MASTER_PORT = 3310
7
7
  SLAVE_ID = "2"
@@ -1,7 +1,7 @@
1
- require 'integration/helpers/mysql_helper'
1
+ require 'integration/support/mysql_setup_helper'
2
2
 
3
3
  shared_examples_for "a MySQL MasterSlaveAdapter" do
4
- include MysqlHelper
4
+ include MysqlSetupHelper
5
5
 
6
6
  let(:configuration) do
7
7
  {
@@ -20,7 +20,7 @@ shared_examples_for "a MySQL MasterSlaveAdapter" do
20
20
  }
21
21
  end
22
22
 
23
- let(:test_table) { MysqlHelper::TEST_TABLE }
23
+ let(:test_table) { MysqlSetupHelper::TEST_TABLE }
24
24
 
25
25
  def connection
26
26
  ActiveRecord::Base.connection