read_from_slave 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -1,9 +1,11 @@
1
1
  Read_from_slave
2
2
 
3
- Read_from_slave for Rails enables database reads from a slave database, while writes continue to go to the master
3
+ Read_from_slave for Rails enables database reads from one or more slave databases, while writes continue to go to the master
4
4
 
5
5
  Read_from_slave will work with Rails 2.2 and above, including Rails 3 versions.
6
6
 
7
+ Note that this version (0.5.x) supports multiple slave databases, but this caused an incompatibility in the configuration - your database.yml file must be updated before you can use this version.
8
+
7
9
  Installation
8
10
 
9
11
  gem install read_from_slave
@@ -16,24 +18,82 @@ In config/environments/production.rb (for instance)
16
18
 
17
19
  In config/database.yml
18
20
 
19
- production:
20
- adapter: mysql
21
- database: mydatabase
22
- username: myuser
23
- password: mypassword
24
- host: my.main.database.server.com
25
- port: 3306
26
-
27
- slave_for_mydatabase:
28
- adapter: mysql
29
- database: mydatabase
30
- username: myuser
31
- password: mypassword
32
- socket: /var/lib/mysql/mysql.sock
21
+ production:
22
+ adapter: mysql
23
+ database: mydatabase
24
+ username: myuser
25
+ password: mypassword
26
+ host: my.main.database.server.com
27
+ port: 3306
28
+ slaves:
29
+ primary_slave: slave_for_reads
30
+ slave_2: slave_for_reporting
31
+
32
+ slave_for_reads:
33
+ adapter: mysql
34
+ database: mydatabase
35
+ username: myuser
36
+ password: mypassword
37
+ socket: /var/lib/mysql/mysql.sock
38
+
39
+ slave_for_reporting:
40
+ adapter: mysql
41
+ database: mydatabase
42
+ username: myuser
43
+ password: mypassword
44
+ host: my.slave.database.server.com
33
45
 
34
46
  Just use the regular YAML format to specify your slave database, it could equally well be on
35
47
  another server as the local example given above.
36
48
 
49
+ In the example above, primary_slave and slave_2 are names that are used to generate methods you can use to specify which slave to use.
50
+ slave_for_reads and slave_for_reporting is the yaml key that is used to make the connection to your slave database.
51
+
52
+ You can have any number of slaves configured. To connect to the slaves:
53
+
54
+ ActiveRecord::Base.with_primary_slave do
55
+ User.last
56
+ end
57
+
58
+ ActiveRecord::Base.with_slave_2 do
59
+ User.last
60
+ end
61
+
62
+ with_primary_slave and with_slave_2 are dynamically created based on the keys provided in the yaml file. Everything
63
+ inside the block with read from the corresponding slave database specified in the yaml file.
64
+
65
+ You must have one slave with the primary_slave key. By default, all the reads will occur on the primary_slave,
66
+ in the example above, and not require you to use the with_primary_slave method. You actually never need to use
67
+ the with_primary_slave method as that slave will alwaysbe used if not inside a with... method block. So if you only have
68
+ 1 slave, you don't ever need to worry about the with... methods.
69
+
70
+ If you have multiple slaves, you will want to make sure you specify slave configurations for each environment, even if you
71
+ don't have slaves in every environment.
72
+
73
+ development:
74
+ adapter: mysql
75
+ database: mydatabase
76
+ username: myuser
77
+ password: mypassword
78
+ host: my.main.database.server.com
79
+ port: 3306
80
+ slaves:
81
+ primary_slave: development
82
+ slave_2: development
83
+
84
+ The reason is, your code will have with_primary_slave and with_slave_2 methods because that is what you need in production,
85
+ but you will get undefined method errors in development because they won't be generated unless your development configuration
86
+ specifies slaves. Just specifying the slave keys back to the development configuration should serve your needs.
87
+
88
+ You may have a need where you don't actually want all of your reads to be on the slave. You may want to be much more
89
+ selective in what you put on the slave. For instance, perhaps you want everything on the master except large reports.
90
+ You can change the default behavior of read_from_slave by setting:
91
+
92
+ ReadFromSlave.all_reads_on_slave = false
93
+
94
+ in your environment.rb file. This will make all reads on the master by default and reads will only be on the slave inside
95
+ the with... method blocks.
96
+
37
97
  Phusion Passenger
38
98
 
39
99
  Note that if you are using Passenger, you need to make sure that the slave database is reconnected
@@ -45,10 +105,10 @@ The safest thing to do is to have something like this in your production.rb or e
45
105
 
46
106
  PhusionPassenger.on_event(:starting_worker_process) do |forked|
47
107
  if forked
48
- # We're in smart spawning mode.
108
+ # We're in smart spawning mode.
49
109
  ActiveRecord::Base.establish_slave_connections
50
110
  else
51
- # We're in conservative spawning mode. We don't need to do anything.
111
+ # We're in conservative spawning mode. We don't need to do anything.
52
112
  end
53
113
  end
54
114
 
@@ -63,18 +123,14 @@ Clone the git repository, and you can run the read_from_slave tests or entire Ac
63
123
  $ rake test
64
124
  ...snip..
65
125
  Finished in 0.046365 seconds.
66
-
126
+
67
127
  7 tests, 7 assertions, 0 failures, 0 errors
68
-
128
+
69
129
  $ rake test_with_active_record
70
130
  ...snip...
71
131
  Finished in 51.904306 seconds.
72
-
73
- 2057 tests, 6685 assertions, 0 failures, 0 errors
74
132
 
75
- Todo
76
-
77
- * Support a pool of multiple slaves
133
+ 2057 tests, 6685 assertions, 0 failures, 0 errors
78
134
 
79
135
  References
80
136
 
@@ -93,4 +149,5 @@ another one, proxy connection approach
93
149
  looks like it won't work with apps that talk to multiple (master) databases
94
150
  more complex than read_from_slave
95
151
 
96
- (c) 2009 Stephen Sykes
152
+ (c) 2009-2011 Stephen Sykes
153
+ Thanks to Kevin Tyll for contributing the multiple slave feature
data/README.textile CHANGED
@@ -1,9 +1,11 @@
1
1
  h1. Read_from_slave
2
2
 
3
- h4. Read_from_slave for Rails enables database reads from a slave database, while writes continue to go to the master
3
+ h4. Read_from_slave for Rails enables database reads from one or more slave databases, while writes continue to go to the master
4
4
 
5
5
  Read_from_slave will work with Rails 2.2 and above, including Rails 3 versions.
6
6
 
7
+ Note that this version (0.5.x) supports multiple slave databases, but this caused an incompatibility in the configuration - your database.yml file must be updated before you can use this version.
8
+
7
9
  h2. Installation
8
10
 
9
11
  <pre>
@@ -26,26 +28,96 @@ In config/database.yml
26
28
 
27
29
  <pre>
28
30
  <code>
29
- production:
30
- adapter: mysql
31
- database: mydatabase
32
- username: myuser
33
- password: mypassword
34
- host: my.main.database.server.com
35
- port: 3306
36
-
37
- slave_for_mydatabase:
38
- adapter: mysql
39
- database: mydatabase
40
- username: myuser
41
- password: mypassword
42
- socket: /var/lib/mysql/mysql.sock
31
+ production:
32
+ adapter: mysql
33
+ database: mydatabase
34
+ username: myuser
35
+ password: mypassword
36
+ host: my.main.database.server.com
37
+ port: 3306
38
+ slaves:
39
+ primary_slave: slave_for_reads
40
+ slave_2: slave_for_reporting
41
+
42
+ slave_for_reads:
43
+ adapter: mysql
44
+ database: mydatabase
45
+ username: myuser
46
+ password: mypassword
47
+ socket: /var/lib/mysql/mysql.sock
48
+
49
+ slave_for_reporting:
50
+ adapter: mysql
51
+ database: mydatabase
52
+ username: myuser
53
+ password: mypassword
54
+ host: my.slave.database.server.com
43
55
  </code>
44
56
  </pre>
45
57
 
46
58
  Just use the regular YAML format to specify your slave database, it could equally well be on
47
59
  another server as the local example given above.
48
60
 
61
+ In the example above, primary_slave and slave_2 are names that are used to generate methods you can use to specify which slave to use.
62
+ slave_for_reads and slave_for_reporting is the yaml key that is used to make the connection to your slave database.
63
+
64
+ You can have any number of slaves configured. To connect to the slaves:
65
+
66
+ <pre>
67
+ <code>
68
+ ActiveRecord::Base.with_primary_slave do
69
+ User.last
70
+ end
71
+
72
+ ActiveRecord::Base.with_slave_2 do
73
+ User.last
74
+ end
75
+ </pre>
76
+ </code>
77
+
78
+ with_primary_slave and with_slave_2 are dynamically created based on the keys provided in the yaml file. Everything
79
+ inside the block with read from the corresponding slave database specified in the yaml file.
80
+
81
+ You must have one slave with the primary_slave key. By default, all the reads will occur on the primary_slave,
82
+ in the example above, and not require you to use the with_primary_slave method. You actually never need to use
83
+ the with_primary_slave method as that slave will alwaysbe used if not inside a with... method block. So if you only have
84
+ 1 slave, you don't ever need to worry about the with... methods.
85
+
86
+ If you have multiple slaves, you will want to make sure you specify slave configurations for each environment, even if you
87
+ don't have slaves in every environment.
88
+
89
+ <pre>
90
+ <code>
91
+ development:
92
+ adapter: mysql
93
+ database: mydatabase
94
+ username: myuser
95
+ password: mypassword
96
+ host: my.main.database.server.com
97
+ port: 3306
98
+ slaves:
99
+ primary_slave: development
100
+ slave_2: development
101
+ </pre>
102
+ </code>
103
+
104
+ The reason is, your code will have with_primary_slave and with_slave_2 methods because that is what you need in production,
105
+ but you will get undefined method errors in development because they won't be generated unless your development configuration
106
+ specifies slaves. Just specifying the slave keys back to the development configuration should serve your needs.
107
+
108
+ You may have a need where you don't actually want all of your reads to be on the slave. You may want to be much more
109
+ selective in what you put on the slave. For instance, perhaps you want everything on the master except large reports.
110
+ You can change the default behavior of read_from_slave by setting:
111
+
112
+ <pre>
113
+ <code>
114
+ ReadFromSlave.all_reads_on_slave = false
115
+ </pre>
116
+ </code>
117
+
118
+ in your environment.rb file. This will make all reads on the master by default and reads will only be on the slave inside
119
+ the with... method blocks.
120
+
49
121
  h2. Phusion Passenger
50
122
 
51
123
  Note that if you are using Passenger, you need to make sure that the slave database is reconnected
@@ -92,10 +164,6 @@ Finished in 51.904306 seconds.
92
164
  </code>
93
165
  </pre>
94
166
 
95
- h2. Todo
96
-
97
- * Support a pool of multiple slaves
98
-
99
167
  h2. References
100
168
 
101
169
  * "Masochism":http://github.com/technoweenie/masochism/tree/master
@@ -112,3 +180,4 @@ h2. References
112
180
 
113
181
 
114
182
  (c) 2009 Stephen Sykes
183
+ Thanks to Kevin Tyll for contributing the multiple slave feature
data/Rakefile CHANGED
@@ -19,20 +19,3 @@ Rake::TestTask.new(:test_read_from_slave) do |t|
19
19
  t.test_files = ReadFromSlave::Test.test_files
20
20
  t.verbose = true
21
21
  end
22
-
23
- begin
24
- require 'jeweler'
25
- Jeweler::Tasks.new do |s|
26
- s.name = "read_from_slave"
27
- s.summary = "Read_from_slave - Utilise your slave databases with rails"
28
- s.email = "sdsykes@gmail.com"
29
- s.homepage = "http://github.com/sdsykes/read_from_slave"
30
- s.description = "Read_from_slave for Rails enables database reads from a slave database, while writes continue to go to the master"
31
- s.authors = ["Stephen Sykes"]
32
- s.files = FileList["[A-Z]*", "{lib,test}/**/*"]
33
- end
34
- Jeweler::GemcutterTasks.new
35
- rescue LoadError
36
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://
37
- gems.github.com"
38
- end
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- :minor: 4
2
+ :minor: 5
3
3
  :build:
4
4
  :major: 0
5
5
  :patch: 0
@@ -1,4 +1,4 @@
1
- # Read_from_slave for Rails enables database reads from a slave database, while writes continue
1
+ # Read_from_slave for Rails enables database reads from one or more slave databases, while writes continue
2
2
  # to go to the master
3
3
  # To use read_from_slave you must install the gem, configure the gem in your environment file,
4
4
  # and setup your database.yml file with an entry for your slave database.
@@ -12,7 +12,7 @@
12
12
  #
13
13
  # config.gem "read_from_slave"
14
14
  #
15
- # In config/database.yml
15
+ # In config/database.yml
16
16
  #
17
17
  # production:
18
18
  # adapter: mysql
@@ -21,16 +21,25 @@
21
21
  # password: mypassword
22
22
  # host: my.main.database.server.com
23
23
  # port: 3306
24
+ # slaves:
25
+ # slave_1: slave_for_reads
26
+ # slave_2: slave_for_reporting
24
27
  #
25
- # slave_for_mydatabase:
28
+ # slave_for_reads:
26
29
  # adapter: mysql
27
30
  # database: mydatabase
28
31
  # username: myuser
29
32
  # password: mypassword
30
33
  # socket: /var/lib/mysql/mysql.sock
31
34
  #
32
- # Note that if you have multiple databases you can also configure multiple slaves - use the
33
- # database name after slave_for_ in the configuration.
35
+ # slave_for_reporting:
36
+ # adapter: mysql
37
+ # database: mydatabase
38
+ # username: myuser
39
+ # password: mypassword
40
+ # host: my.slave.database.server.com
41
+ #
42
+ # Note that if you have multiple databases you can also configure multiple slaves.
34
43
  #
35
44
  # === References
36
45
  # * "Masochism":http://github.com/technoweenie/masochism/tree/master
@@ -58,7 +67,7 @@ module ReadFromSlave
58
67
  alias_method_chain :connection, :read_from_slave
59
68
  end
60
69
  end
61
-
70
+
62
71
  begin
63
72
  calculation_base = ActiveRecord::Relation # rails 3
64
73
  calculation_base.send(:include, CalculationMethod)
@@ -72,6 +81,26 @@ module ReadFromSlave
72
81
  end
73
82
  end
74
83
  end
84
+
85
+ def default_to_master!
86
+ base = ActiveRecord::Base
87
+ base.class_eval do
88
+ class << self
89
+ alias_method_chain :connection, :slave_db_scope unless ReadFromSlave.all_reads_on_slave
90
+ end
91
+ end
92
+ end
93
+
94
+ @@all_reads_on_slave = true
95
+ def all_reads_on_slave=(all_reads)
96
+ @@all_reads_on_slave = all_reads
97
+ default_to_master!
98
+ end
99
+
100
+ def all_reads_on_slave
101
+ @@all_reads_on_slave
102
+ end
103
+
75
104
  end
76
105
 
77
106
  module InstanceMethods
@@ -92,84 +121,127 @@ module ReadFromSlave
92
121
  Thread.current[:read_from_slave] = false
93
122
  end
94
123
 
124
+ ActiveRecord::Base.connection.instance_variable_get(:@config)[:slaves].each_key do |slave_name|
125
+ eval <<-EOM
126
+ def with_#{slave_name}(&block)
127
+ Thread.current[:with_#{slave_name}_count] ||= 0
128
+ Thread.current[:with_#{slave_name}_count] += 1
129
+ yield
130
+ ensure
131
+ Thread.current[:with_#{slave_name}_count] -= 1
132
+ end
133
+ EOM
134
+ end if ActiveRecord::Base.connection.instance_variable_get(:@config)[:slaves]
135
+
136
+ def connection_with_slave_db_scope
137
+ slaves.each_key do |slave_name|
138
+ if Thread.current[:"with_#{slave_name}_count"].to_i > 0
139
+ return connection_without_slave_db_scope
140
+ end
141
+ end
142
+ connection_without_read_from_slave
143
+ end
144
+
95
145
  def connection_with_read_from_slave
96
146
  normal_connection = connection_without_read_from_slave
97
147
  if Thread.current[:read_from_slave] && normal_connection.open_transactions == 0
98
- Thread.current[:read_from_slave_uses] = :slave # for testing use
99
- slave_connection
148
+ slaves.each do |slave_name, slave_config|
149
+ if Thread.current[:"with_#{slave_name}_count"].to_i > 0
150
+ Thread.current[:read_from_slave_uses] = slave_name # for testing use
151
+ return slave_connection(slave_config)
152
+ end
153
+ end
154
+ # If we're not in a with_slave block, default to the primary slave
155
+ Thread.current[:read_from_slave_uses] = primary_slave_name # for testing use
156
+ return slave_connection(primary_slave_config)
100
157
  else
101
158
  Thread.current[:read_from_slave_uses] = :master
102
- normal_connection
159
+ return normal_connection
103
160
  end
104
161
  end
105
162
 
106
- # Returns a connection to the slave database, or to the regular database if
107
- # no slave is configured
108
- #
109
- def slave_connection
110
- (@slave_model || slave_model).connection_without_read_from_slave
163
+ # Returns a connection to the slave database, or to the regular database if
164
+ # no slave is configured
165
+ #
166
+ def slave_connection(slave_config)
167
+ @slave_model ||= {}
168
+ (@slave_model[slave_config] || slave_model(slave_config)).connection_without_read_from_slave
111
169
  end
112
170
 
113
171
 
114
- # Returns an AR model class that has a connection to the appropriate slave db
115
- #
116
- def slave_model
117
- db_name = master_database_name
118
- if slave_config_for(db_name)
119
- unless @@slave_models[db_name]
120
- slave_model_name = "ReadFromSlaveFor_#{db_name}"
121
- @@slave_models[db_name] = eval %{
172
+ # Returns an AR model class that has a connection to the appropriate slave db
173
+ #
174
+ def slave_model(slave_config)
175
+ if slave_config_for(slave_config)
176
+ unless @@slave_models[slave_config]
177
+ slave_model_name = "ReadFromSlaveFor_#{slave_config}"
178
+ @@slave_models[slave_config] = eval %{
122
179
  class #{slave_model_name} < ActiveRecord::Base
123
180
  self.abstract_class = true
124
- establish_slave_connection_for('#{db_name}')
181
+ establish_slave_connection_for('#{slave_config}')
125
182
  end
126
183
  #{slave_model_name}
127
184
  }
128
185
  end
129
- @slave_model = @@slave_models[db_name]
186
+ @slave_model[slave_config] = @@slave_models[slave_config]
130
187
  else
131
- @slave_model = self
188
+ @slave_model[slave_config] = self
132
189
  end
133
190
  end
134
191
 
135
- # Returns the name of the database in use, as given in the database.yml file
136
- #
137
- def master_database_name
138
- connection_without_read_from_slave.instance_variable_get(:@config)[:database]
192
+ # # Returns the name of the database in use, as given in the database.yml file
193
+ # #
194
+ # def master_database_name
195
+ # connection_without_read_from_slave.instance_variable_get(:@config)[:database]
196
+ # end
197
+
198
+ # Returns a hash of the slave databases, as given in the database.yml file
199
+ def slaves
200
+ connection_without_read_from_slave.instance_variable_get(:@config)[:slaves] || {}
201
+ end
202
+
203
+ # Returns the first slave defined in database.yml which will be used by default for reads
204
+ def primary_slave_config
205
+ slaves[primary_slave_name]
139
206
  end
140
207
 
141
- # Returns the config for the associated slave database for this master,
142
- # as given in the database.yml file
143
- #
144
- def slave_config_for(master)
145
- configurations["slave_for_#{master}"]
208
+ # Returns the first slave defined in database.yml which will be used by default for reads
209
+ def primary_slave_name
210
+ :primary_slave
146
211
  end
147
212
 
148
- # Establishes a connection to the slave database that is configured for
149
- # the database name provided
150
- #
151
- def establish_slave_connection_for(master)
152
- conn_spec = slave_config_for(master)
213
+ # Returns the config for the associated slave database for this master,
214
+ # as given in the database.yml file
215
+ #
216
+ def slave_config_for(slave_config)
217
+ configurations[slave_config]
218
+ end
219
+
220
+ # Establishes a connection to the slave database that is configured for
221
+ # the database name provided
222
+ #
223
+ def establish_slave_connection_for(slave_config)
224
+ conn_spec = slave_config_for(slave_config)
153
225
  establish_connection(conn_spec) if conn_spec
154
226
  end
155
227
 
156
228
  # Re-establishes connections to all the slave databases that
157
- # have been used so far. Use this in your
229
+ # have been used so far. Use this in your
158
230
  # PhusionPassenger.on_event(:starting_worker_process) block if required.
159
231
  #
160
232
  def establish_slave_connections
161
- @@slave_models.each do |db_name, model|
162
- model.establish_slave_connection_for(db_name)
233
+ @@slave_models.each do |slave_config, model|
234
+ model.establish_slave_connection_for(slave_config)
163
235
  end
164
236
  end
165
237
  end
166
-
238
+
167
239
  module CalculationMethod
168
240
  def calculate_with_read_from_slave(*args)
169
241
  Thread.current[:read_from_slave] = true
170
242
  calculate_without_read_from_slave(*args)
171
243
  ensure
172
- Thread.current[:read_from_slave] = false
244
+ Thread.current[:read_from_slave] = false
173
245
  end
174
246
  end
175
247
  end
data/test/helper.rb CHANGED
@@ -12,6 +12,7 @@ module ReadFromSlave
12
12
  load_models
13
13
  load(SCHEMA_ROOT + "/schema.rb")
14
14
  require 'test/unit'
15
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'read_from_slave')
15
16
  end
16
17
 
17
18
  def test_files
@@ -25,49 +26,58 @@ module ReadFromSlave
25
26
  private
26
27
 
27
28
  def setup_constants
28
- set_constant('TEST_ROOT') {File.expand_path(File.dirname(__FILE__))}
29
- set_constant('SCHEMA_ROOT') {TEST_ROOT + "/schema"}
29
+ set_constant('TEST_ROOT') { File.expand_path(File.dirname(__FILE__)) }
30
+ set_constant('SCHEMA_ROOT') { TEST_ROOT + "/schema" }
30
31
  end
31
-
32
+
32
33
  def make_sqlite_config
33
34
  ActiveRecord::Base.configurations = {
34
- 'rfs' => {
35
- :adapter => 'sqlite3',
36
- :database => 'test_db',
37
- :timeout => 5000
38
- },
39
- 'slave_for_test_db' => {
40
- :adapter => 'sqlite3',
41
- :database => 'test_db',
42
- :timeout => 5000
43
- }
35
+ 'rfs' => {
36
+ :adapter => 'sqlite3',
37
+ :database => 'test_db',
38
+ :timeout => 5000,
39
+ :slaves =>
40
+ {:primary_slave => 'primary_slave',
41
+ :slave_2 => 'slave_2'
42
+ }
43
+ },
44
+ 'primary_slave' => {
45
+ :adapter => 'sqlite3',
46
+ :database => 'test_db',
47
+ :timeout => 5000
48
+ },
49
+ 'slave_2' => {
50
+ :adapter => 'sqlite3',
51
+ :database => 'test_db',
52
+ :timeout => 5000
53
+ }
44
54
  }
45
55
  end
46
-
56
+
47
57
  def load_models
48
- test_model_files.each {|f| require File.join(File.dirname(__FILE__), "models", f)}
58
+ test_model_files.each { |f| require File.join(File.dirname(__FILE__), "models", f) }
49
59
  end
50
60
 
51
61
  def make_sqlite_connection
52
62
  ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['rfs'])
53
63
  end
54
-
64
+
55
65
  def set_constant(constant)
56
66
  Object.const_set(constant, yield) unless Object.const_defined?(constant)
57
67
  end
58
-
68
+
59
69
  def glob(pattern)
60
70
  Dir.glob(pattern)
61
71
  end
62
72
  end
63
73
  end
64
-
74
+
65
75
  class ActiveRecordTest < Test
66
76
  class << self
67
77
  def setup
68
78
  setup_constants
69
79
  end
70
-
80
+
71
81
  def test_files
72
82
  glob("#{AR_TEST_SUITE}/cases/**/*_test.rb").sort
73
83
  end
@@ -79,10 +89,10 @@ module ReadFromSlave
79
89
  private
80
90
 
81
91
  def setup_constants
82
- set_constant('MYSQL_DB_USER') {'rails'}
83
- set_constant('AR_TEST_SUITE') {find_active_record_test_suite}
92
+ set_constant('MYSQL_DB_USER') { 'rails' }
93
+ set_constant('AR_TEST_SUITE') { find_active_record_test_suite }
84
94
  end
85
-
95
+
86
96
  def find_active_record_test_suite
87
97
  ts = ($:).grep(/activerecord/).last.split('/')
88
98
  ts.pop
@@ -4,7 +4,7 @@ ReadFromSlave::Test.setup
4
4
 
5
5
  class ReadFromSlaveTest < ActiveSupport::TestCase
6
6
  test "slave connection should be different from normal connection" do
7
- assert_not_equal Course.connection_without_read_from_slave, Course.slave_connection
7
+ assert_not_equal Course.connection_without_read_from_slave, Course.slave_connection(Course.primary_slave_config)
8
8
  end
9
9
 
10
10
  test "should be able to write and read from database" do
@@ -21,7 +21,7 @@ class ReadFromSlaveTest < ActiveSupport::TestCase
21
21
  test "should read from slave" do
22
22
  Course.create(:name=>"Saw playing")
23
23
  x = Course.find(:first)
24
- assert_equal :slave, Thread.current[:read_from_slave_uses]
24
+ assert_equal :primary_slave, Thread.current[:read_from_slave_uses]
25
25
  end
26
26
 
27
27
  test "should reload from master" do
@@ -32,9 +32,9 @@ class ReadFromSlaveTest < ActiveSupport::TestCase
32
32
  end
33
33
 
34
34
  test "should get new slave connection when calling establish_slave_connections" do
35
- conn = Course.slave_connection
35
+ conn = Course.slave_connection(Course.primary_slave_config)
36
36
  ActiveRecord::Base.establish_slave_connections
37
- assert_not_equal conn, Course.slave_connection
37
+ assert_not_equal conn, Course.slave_connection(Course.primary_slave_config)
38
38
  end
39
39
 
40
40
  test "should not get new master connection when calling establish_slave_connections" do
@@ -44,8 +44,33 @@ class ReadFromSlaveTest < ActiveSupport::TestCase
44
44
  end
45
45
 
46
46
  test "count should use the slave" do
47
+ count = Course.count
47
48
  Course.create(:name=>"Saw playing")
48
- assert_equal 1, Course.count
49
- assert_equal :slave, Thread.current[:read_from_slave_uses]
49
+ assert_equal count + 1, Course.count
50
+ assert_equal :primary_slave, Thread.current[:read_from_slave_uses]
51
+ end
52
+
53
+ test "primary_slave_config should return the right configuration" do
54
+ assert_equal 'primary_slave', Course.primary_slave_config
55
+ end
56
+
57
+ test "slave is not used by default when all_reads_on_slave is false" do
58
+ ReadFromSlave.all_reads_on_slave = false
59
+ Course.create(:name=>"Saw playing")
60
+ assert_equal :master, Thread.current[:read_from_slave_uses]
61
+ Course.first
62
+ assert_equal :master, Thread.current[:read_from_slave_uses]
63
+ end
64
+
65
+ test "correct slave is used with block" do
66
+ Course.create(:name=>"Saw playing")
67
+ Course.with_primary_slave do
68
+ Course.first
69
+ assert_equal :primary_slave, Thread.current[:read_from_slave_uses]
70
+ end
71
+ Course.with_slave_2 do
72
+ Course.first
73
+ assert_equal :slave_2, Thread.current[:read_from_slave_uses]
74
+ end
50
75
  end
51
76
  end
data/test/setup.rb CHANGED
@@ -4,4 +4,3 @@ require 'rubygems'
4
4
  #gem 'activerecord', '= 2.3.8'
5
5
 
6
6
  require 'active_record'
7
- require File.join(File.dirname(__FILE__), '..', 'lib', 'read_from_slave')
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: read_from_slave
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 11
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 4
8
+ - 5
9
9
  - 0
10
- version: 0.4.0
10
+ version: 0.5.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Stephen Sykes
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-08-14 00:00:00 +03:00
18
+ date: 2011-06-01 00:00:00 +03:00
19
19
  default_executable:
20
20
  dependencies: []
21
21