master_slave_adapter 1.0.0.beta2 → 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.
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