seamless_database_pool 1.0.5 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -48,9 +48,9 @@ describe "SeamlessDatabasePoolAdapter ActiveRecord::Base extension" do
48
48
  logger = ActiveRecord::Base.logger
49
49
  weights = {master_connection => 1, read_connection_1 => 1, read_connection_2 => 2}
50
50
 
51
- ActiveRecord::Base.should_receive(:writer_connection).with(:adapter => 'writer', :host => 'master_host', :username => 'user', :pool_weight => 1).and_return(master_connection)
52
- ActiveRecord::Base.should_receive(:reader_connection).with(:adapter => 'reader', :host => 'read_host_1', :username => 'user', :pool_weight => 1).and_return(read_connection_1)
53
- ActiveRecord::Base.should_receive(:reader_connection).with(:adapter => 'reader', :host => 'read_host_2', :username => 'user', :pool_weight => 2).and_return(read_connection_2)
51
+ ActiveRecord::Base.should_receive(:writer_connection).with('adapter' => 'writer', 'host' => 'master_host', 'username' => 'user', 'pool_weight' => 1).and_return(master_connection)
52
+ ActiveRecord::Base.should_receive(:reader_connection).with('adapter' => 'reader', 'host' => 'read_host_1', 'username' => 'user', 'pool_weight' => 1).and_return(read_connection_1)
53
+ ActiveRecord::Base.should_receive(:reader_connection).with('adapter' => 'reader', 'host' => 'read_host_2', 'username' => 'user', 'pool_weight' => 2).and_return(read_connection_2)
54
54
 
55
55
  klass = mock(:class)
56
56
  ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.should_receive(:adapter_class).with(master_connection).and_return(klass)
@@ -78,303 +78,281 @@ describe "SeamlessDatabasePoolAdapter" do
78
78
  @pool_connection = connection_class.new(nil, mock(:logger), @master_connection, [@read_connection_1, @read_connection_2], weights)
79
79
  end
80
80
 
81
- it "should initialize the connection pool" do
82
- @pool_connection.master_connection.should == @master_connection
83
- @pool_connection.read_connections.should == [@read_connection_1, @read_connection_2]
84
- @pool_connection.all_connections.should == [@master_connection, @read_connection_1, @read_connection_2]
85
- @pool_connection.pool_weight(@master_connection).should == 1
86
- @pool_connection.pool_weight(@read_connection_1).should == 1
87
- @pool_connection.pool_weight(@read_connection_2).should == 2
88
- end
81
+ context "selecting a connection from the pool" do
82
+ it "should initialize the connection pool" do
83
+ @pool_connection.master_connection.should == @master_connection
84
+ @pool_connection.read_connections.should == [@read_connection_1, @read_connection_2]
85
+ @pool_connection.all_connections.should == [@master_connection, @read_connection_1, @read_connection_2]
86
+ @pool_connection.pool_weight(@master_connection).should == 1
87
+ @pool_connection.pool_weight(@read_connection_1).should == 1
88
+ @pool_connection.pool_weight(@read_connection_2).should == 2
89
+ end
89
90
 
90
- it "should return the current read connection" do
91
- SeamlessDatabasePool.should_receive(:read_only_connection).with(@pool_connection).and_return(:current)
92
- @pool_connection.current_read_connection.should == :current
93
- end
91
+ it "should return the current read connection" do
92
+ SeamlessDatabasePool.should_receive(:read_only_connection).with(@pool_connection).and_return(:current)
93
+ @pool_connection.current_read_connection.should == :current
94
+ end
94
95
 
95
- it "should select a random read connection" do
96
- mock_connection = stub(:connection, :active? => true)
97
- @pool_connection.should_receive(:available_read_connections).and_return([:fake1, :fake2, mock_connection])
98
- @pool_connection.should_receive(:rand).with(3).and_return(2)
99
- @pool_connection.random_read_connection.should == mock_connection
100
- end
96
+ it "should select a random read connection" do
97
+ mock_connection = stub(:connection, :active? => true)
98
+ @pool_connection.should_receive(:available_read_connections).and_return([:fake1, :fake2, mock_connection])
99
+ @pool_connection.should_receive(:rand).with(3).and_return(2)
100
+ @pool_connection.random_read_connection.should == mock_connection
101
+ end
101
102
 
102
- it "should select the master connection if the read pool is empty" do
103
- @pool_connection.should_receive(:available_read_connections).and_return([])
104
- @pool_connection.random_read_connection.should == @master_connection
105
- end
103
+ it "should select the master connection if the read pool is empty" do
104
+ @pool_connection.should_receive(:available_read_connections).and_return([])
105
+ @pool_connection.random_read_connection.should == @master_connection
106
+ end
106
107
 
107
- it "should use the master connection in a block" do
108
- connection_class = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(@master_connection)
109
- connection = connection_class.new(nil, mock(:logger), @master_connection, [@read_connection_1], {@read_connection_1 => 1})
110
- connection.random_read_connection.should == @read_connection_1
111
- connection.use_master_connection do
112
- connection.random_read_connection.should == @master_connection
108
+ it "should use the master connection in a block" do
109
+ connection_class = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(@master_connection)
110
+ connection = connection_class.new(nil, mock(:logger), @master_connection, [@read_connection_1], {@read_connection_1 => 1})
111
+ connection.random_read_connection.should == @read_connection_1
112
+ connection.use_master_connection do
113
+ connection.random_read_connection.should == @master_connection
114
+ end
115
+ connection.random_read_connection.should == @read_connection_1
113
116
  end
114
- connection.random_read_connection.should == @read_connection_1
115
- end
116
117
 
117
- it "should use the master connection inside a transaction" do
118
- connection_class = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(@master_connection)
119
- connection = connection_class.new(nil, mock(:logger), @master_connection, [@read_connection_1], {@read_connection_1 => 1})
120
- @master_connection.should_receive(:transaction).with(true).and_yield
121
- @master_connection.should_receive(:select).with('Transaction SQL', nil)
122
- @read_connection_1.should_receive(:select).with('SQL 1', nil)
123
- @read_connection_1.should_receive(:select).with('SQL 2', nil)
118
+ it "should use the master connection inside a transaction" do
119
+ connection_class = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(@master_connection)
120
+ connection = connection_class.new(nil, mock(:logger), @master_connection, [@read_connection_1], {@read_connection_1 => 1})
121
+ @master_connection.should_receive(:transaction).and_yield
122
+ @master_connection.should_receive(:select).with('Transaction SQL', nil)
123
+ @read_connection_1.should_receive(:select).with('SQL 1', nil)
124
+ @read_connection_1.should_receive(:select).with('SQL 2', nil)
124
125
 
125
- SeamlessDatabasePool.use_persistent_read_connection do
126
- connection.send(:select, 'SQL 1', nil)
127
- connection.transaction do
128
- connection.send(:select, 'Transaction SQL', nil)
126
+ SeamlessDatabasePool.use_persistent_read_connection do
127
+ connection.send(:select, 'SQL 1', nil)
128
+ connection.transaction do
129
+ connection.send(:select, 'Transaction SQL', nil)
130
+ end
131
+ connection.send(:select, 'SQL 2', nil)
129
132
  end
130
- connection.send(:select, 'SQL 2', nil)
131
133
  end
132
134
  end
133
-
134
- # Read methods
135
-
136
- it "should proxy select methods to a read connection" do
137
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
138
- @read_connection_1.should_receive(:select).with('SQL').and_return(:retval)
139
- @pool_connection.send(:select, 'SQL').should == :retval
140
- end
141
-
142
- it "should proxy execute methods to a read connection" do
143
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
144
- @read_connection_1.should_receive(:execute).with('SQL').and_return(:retval)
145
- @pool_connection.execute('SQL').should == :retval
146
- end
147
-
148
- it "should proxy select_rows methods to a read connection" do
149
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
150
- @read_connection_1.should_receive(:select_rows).with('SQL').and_return(:retval)
151
- @pool_connection.select_rows('SQL').should == :retval
152
- end
153
135
 
154
- # Master connection methods
155
-
156
- it "should proxy insert method to the master connection" do
157
- @master_connection.should_receive(:insert).with('SQL', nil, nil, nil, nil).and_return(:retval)
158
- @pool_connection.insert('SQL').should == :retval
159
- end
136
+ context "read connection methods" do
137
+ it "should proxy select methods to a read connection" do
138
+ @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
139
+ @read_connection_1.should_receive(:select).with('SQL').and_return(:retval)
140
+ @pool_connection.send(:select, 'SQL').should == :retval
141
+ end
160
142
 
161
- it "should proxy update method to the master connection" do
162
- @master_connection.should_receive(:update).with('SQL', nil).and_return(:retval)
163
- @pool_connection.update('SQL').should == :retval
164
- end
143
+ it "should proxy execute methods to a read connection" do
144
+ @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
145
+ @read_connection_1.should_receive(:execute).with('SQL').and_return(:retval)
146
+ @pool_connection.execute('SQL').should == :retval
147
+ end
165
148
 
166
- it "should proxy columns method to the master connection" do
167
- @master_connection.should_receive(:columns).with(:table).and_return(:retval)
168
- @pool_connection.columns(:table).should == :retval
149
+ it "should proxy select_rows methods to a read connection" do
150
+ @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
151
+ @read_connection_1.should_receive(:select_rows).with('SQL').and_return(:retval)
152
+ @pool_connection.select_rows('SQL').should == :retval
153
+ end
169
154
  end
170
155
 
171
- # Fork to all connection methods
156
+ context "master connection methods" do
157
+ it "should proxy insert method to the master connection" do
158
+ @master_connection.should_receive(:insert).with('SQL').and_return(:retval)
159
+ @pool_connection.insert('SQL').should == :retval
160
+ end
172
161
 
173
- it "should fork active? to all connections and return true if all are up" do
174
- @master_connection.should_receive(:active?).and_return(true)
175
- @read_connection_1.should_receive(:active?).and_return(true)
176
- @read_connection_2.should_receive(:active?).and_return(true)
177
- @pool_connection.active?.should == true
178
- end
162
+ it "should proxy update method to the master connection" do
163
+ @master_connection.should_receive(:update).with('SQL').and_return(:retval)
164
+ @pool_connection.update('SQL').should == :retval
165
+ end
179
166
 
180
- it "should fork active? to all connections and return false if one is down" do
181
- @master_connection.should_receive(:active?).and_return(true)
182
- @read_connection_1.should_receive(:active?).and_return(true)
183
- @read_connection_2.should_receive(:active?).and_return(false)
184
- @pool_connection.active?.should == false
167
+ it "should proxy columns method to the master connection" do
168
+ @master_connection.should_receive(:columns).with(:table).and_return(:retval)
169
+ @pool_connection.columns(:table).should == :retval
170
+ end
185
171
  end
186
172
 
187
- it "should fork verify! to all connections" do
188
- @master_connection.should_receive(:verify!).with(5)
189
- @read_connection_1.should_receive(:verify!).with(5)
190
- @read_connection_2.should_receive(:verify!).with(5)
191
- @pool_connection.verify!(5)
192
- end
173
+ context "fork to all connections" do
174
+ it "should fork active? to all connections and return true if all are up" do
175
+ @master_connection.should_receive(:active?).and_return(true)
176
+ @read_connection_1.should_receive(:active?).and_return(true)
177
+ @read_connection_2.should_receive(:active?).and_return(true)
178
+ @pool_connection.active?.should == true
179
+ end
193
180
 
194
- it "should fork disconnect! to all connections" do
195
- @master_connection.should_receive(:disconnect!)
196
- @read_connection_1.should_receive(:disconnect!)
197
- @read_connection_2.should_receive(:disconnect!)
198
- @pool_connection.disconnect!
199
- end
181
+ it "should fork active? to all connections and return false if one is down" do
182
+ @master_connection.should_receive(:active?).and_return(true)
183
+ @read_connection_1.should_receive(:active?).and_return(true)
184
+ @read_connection_2.should_receive(:active?).and_return(false)
185
+ @pool_connection.active?.should == false
186
+ end
200
187
 
201
- it "should fork reconnect! to all connections" do
202
- @master_connection.should_receive(:reconnect!)
203
- @read_connection_1.should_receive(:reconnect!)
204
- @read_connection_2.should_receive(:reconnect!)
205
- @pool_connection.reconnect!
206
- end
188
+ it "should fork verify! to all connections" do
189
+ @master_connection.should_receive(:verify!).with(5)
190
+ @read_connection_1.should_receive(:verify!).with(5)
191
+ @read_connection_2.should_receive(:verify!).with(5)
192
+ @pool_connection.verify!(5)
193
+ end
207
194
 
208
- it "should timeout reconnect! calls to dead servers" do
209
- @read_connection_1.connect_timeout = 0.1
210
- lambda{@pool_connection.reconnect!}.should raise_error("reconnect timed out")
211
- end
195
+ it "should fork disconnect! to all connections" do
196
+ @master_connection.should_receive(:disconnect!)
197
+ @read_connection_1.should_receive(:disconnect!)
198
+ @read_connection_2.should_receive(:disconnect!)
199
+ @pool_connection.disconnect!
200
+ end
212
201
 
213
- it "should fork reset_runtime to all connections" do
214
- @master_connection.should_receive(:reset_runtime).and_return(1)
215
- @read_connection_1.should_receive(:reset_runtime).and_return(2)
216
- @read_connection_2.should_receive(:reset_runtime).and_return(3)
217
- @pool_connection.reset_runtime.should == 6
218
- end
202
+ it "should fork reconnect! to all connections" do
203
+ @master_connection.should_receive(:reconnect!)
204
+ @read_connection_1.should_receive(:reconnect!)
205
+ @read_connection_2.should_receive(:reconnect!)
206
+ @pool_connection.reconnect!
207
+ end
219
208
 
220
- # Reconnection logic
209
+ it "should timeout reconnect! calls to dead servers" do
210
+ @read_connection_1.connect_timeout = 0.1
211
+ lambda{@pool_connection.reconnect!}.should raise_error("reconnect timed out")
212
+ end
221
213
 
222
- it "should proxy requests to a connection" do
223
- args = [:arg1, :arg2]
224
- block = Proc.new{}
225
- @master_connection.should_receive(:select_value).with(*args, &block)
226
- @master_connection.should_not_receive(:active?)
227
- @master_connection.should_not_receive(:reconnect!)
228
- @pool_connection.send(:proxy_connection_method, @master_connection, :select_value, :master, *args, &block)
214
+ it "should fork reset_runtime to all connections" do
215
+ @master_connection.should_receive(:reset_runtime).and_return(1)
216
+ @read_connection_1.should_receive(:reset_runtime).and_return(2)
217
+ @read_connection_2.should_receive(:reset_runtime).and_return(3)
218
+ @pool_connection.reset_runtime.should == 6
219
+ end
229
220
  end
221
+
222
+ context "reconnection" do
223
+ it "should proxy requests to a connection" do
224
+ args = [:arg1, :arg2]
225
+ block = Proc.new{}
226
+ @master_connection.should_receive(:select_value).with(*args, &block)
227
+ @master_connection.should_not_receive(:active?)
228
+ @master_connection.should_not_receive(:reconnect!)
229
+ @pool_connection.send(:proxy_connection_method, @master_connection, :select_value, :master, *args, &block)
230
+ end
230
231
 
231
- it "should try to reconnect dead connections" do
232
- args = [:arg1, :arg2]
233
- block = Proc.new{}
234
- @master_connection.should_receive(:select_value).with(*args, &block).and_raise("SQL ERROR")
235
- @master_connection.should_receive(:active?).and_return(false)
236
- @master_connection.should_receive(:reconnect!)
237
- lambda{@pool_connection.send(:proxy_connection_method, @master_connection, :select_value, :master, *args, &block)}.should raise_error(ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter::DatabaseConnectionError)
238
- end
232
+ it "should try to reconnect dead connections when they become available again" do
233
+ @master_connection.stub!(:select_value).and_raise("SQL ERROR")
234
+ @master_connection.should_receive(:active?).and_return(false, false, true)
235
+ @master_connection.should_receive(:reconnect!)
236
+ now = Time.now
237
+ lambda{@pool_connection.select_value("SQL")}.should raise_error("SQL ERROR")
238
+ Time.stub!(:now).and_return(now + 31)
239
+ lambda{@pool_connection.select_value("SQL")}.should raise_error("SQL ERROR")
240
+ end
239
241
 
240
- it "should not try to reconnect live connections" do
241
- args = [:arg1, :arg2]
242
- block = Proc.new{}
243
- @master_connection.should_receive(:select_value).with(*args, &block).and_raise("SQL ERROR")
244
- @master_connection.should_receive(:active?).and_return(true)
245
- @master_connection.should_not_receive(:reconnect!)
246
- lambda{@pool_connection.send(:proxy_connection_method, @master_connection, :select_value, :master, *args, &block)}.should raise_error("SQL ERROR")
247
- end
242
+ it "should not try to reconnect live connections" do
243
+ args = [:arg1, :arg2]
244
+ block = Proc.new{}
245
+ @master_connection.should_receive(:select_value).with(*args, &block).twice.and_raise("SQL ERROR")
246
+ @master_connection.should_receive(:active?).and_return(true)
247
+ @master_connection.should_not_receive(:reconnect!)
248
+ lambda{@pool_connection.send(:proxy_connection_method, @master_connection, :select_value, :read, *args, &block)}.should raise_error("SQL ERROR")
249
+ end
248
250
 
249
- it "should not try to reconnect a connection during a retry" do
250
- args = [:arg1, :arg2]
251
- block = Proc.new{}
252
- @master_connection.should_receive(:select_value).with(*args, &block).and_raise("SQL ERROR")
253
- @master_connection.should_not_receive(:active?)
254
- @master_connection.should_not_receive(:reconnect!)
255
- lambda{@pool_connection.send(:proxy_connection_method, @master_connection, :select_value, :retry, *args, &block)}.should raise_error("SQL ERROR")
256
- end
251
+ it "should not try to reconnect a connection during a retry" do
252
+ args = [:arg1, :arg2]
253
+ block = Proc.new{}
254
+ @master_connection.should_receive(:select_value).with(*args, &block).and_raise("SQL ERROR")
255
+ @master_connection.should_not_receive(:active?)
256
+ @master_connection.should_not_receive(:reconnect!)
257
+ lambda{@pool_connection.send(:proxy_connection_method, @master_connection, :select_value, :retry, *args, &block)}.should raise_error("SQL ERROR")
258
+ end
257
259
 
258
- it "should try to execute a read statement again after a connection error" do
259
- connection_error = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter::DatabaseConnectionError.new
260
- connection_error.wrapped_exception = StandardError.new("Error")
261
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
262
- @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select, :read, 'SQL').and_raise(connection_error)
263
- @read_connection_1.should_receive(:active?).and_return(true)
264
- @pool_connection.should_not_receive(:suppress_read_connection)
265
- SeamlessDatabasePool.should_not_receive(:set_persistent_read_connection)
266
- @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select, :retry, 'SQL').and_return(:results)
267
- @pool_connection.send(:select, 'SQL').should == :results
268
- end
260
+ it "should try to execute a read statement again after a connection error" do
261
+ connection_error = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter::DatabaseConnectionError.new
262
+ @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
263
+ @read_connection_1.should_receive(:select).with('SQL').and_raise(connection_error)
264
+ @read_connection_1.should_receive(:active?).and_return(true)
265
+ @pool_connection.should_not_receive(:suppress_read_connection)
266
+ SeamlessDatabasePool.should_not_receive(:set_persistent_read_connection)
267
+ @read_connection_1.should_receive(:select).with('SQL').and_return(:results)
268
+ @pool_connection.send(:select, 'SQL').should == :results
269
+ end
269
270
 
270
- it "should not try to execute a read statement again after a connection error if the master connection must be used" do
271
- connection_error = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter::DatabaseConnectionError.new
272
- connection_error.wrapped_exception = StandardError.new("Error")
273
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
274
- @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select, :read, 'SQL').and_raise(connection_error)
275
- @pool_connection.use_master_connection do
276
- lambda{@pool_connection.send(:select, 'SQL')}.should raise_error("Error")
271
+ it "should not try to execute a read statement again after a connection error if the master connection must be used" do
272
+ @master_connection.should_receive(:select).with('SQL').and_raise("Fail")
273
+ @pool_connection.use_master_connection do
274
+ lambda{@pool_connection.send(:select, 'SQL')}.should raise_error("Fail")
275
+ end
277
276
  end
278
- end
279
277
 
280
- it "should not try to execute a read statement again after a non-connection error" do
281
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
282
- @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select, :read, 'SQL').and_raise("SQL Error")
283
- lambda{@pool_connection.send(:select, 'SQL')}.should raise_error("SQL Error")
284
- end
278
+ it "should not try to execute a read statement again after a non-connection error" do
279
+ @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
280
+ @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select, :read, 'SQL').and_raise("SQL Error")
281
+ lambda{@pool_connection.send(:select, 'SQL')}.should raise_error("SQL Error")
282
+ end
285
283
 
286
- it "should use a different connection on a retry if the original connection could not be reconnected" do
287
- connection_error = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter::DatabaseConnectionError.new
288
- connection_error.wrapped_exception = StandardError.new("Error")
289
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1, @read_connection_2)
290
- @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select, :read, 'SQL').and_raise(connection_error)
291
- @read_connection_1.should_receive(:active?).and_return(false)
292
- @pool_connection.should_receive(:suppress_read_connection).with(@read_connection_1, 30)
293
- SeamlessDatabasePool.should_receive(:set_persistent_read_connection).with(@pool_connection, @read_connection_2)
294
- @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_2, :select, :retry, 'SQL').and_return(:results)
295
- @pool_connection.send(:select, 'SQL').should == :results
296
- end
284
+ it "should use a different connection on a retry if the original connection could not be reconnected" do
285
+ @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1, @read_connection_2)
286
+ @read_connection_1.should_receive(:select).with('SQL').and_raise("Fail")
287
+ @read_connection_1.should_receive(:active?).and_return(false)
288
+ @pool_connection.should_receive(:suppress_read_connection).with(@read_connection_1, 30)
289
+ SeamlessDatabasePool.should_receive(:set_persistent_read_connection).with(@pool_connection, @read_connection_2)
290
+ @read_connection_2.should_receive(:select).with('SQL').and_return(:results)
291
+ @pool_connection.send(:select, 'SQL').should == :results
292
+ end
297
293
 
298
- it "should keep track of read connections that can't be reconnected for a set period" do
299
- @pool_connection.available_read_connections.should include(@read_connection_1)
300
- @pool_connection.suppress_read_connection(@read_connection_1, 30)
301
- @pool_connection.available_read_connections.should_not include(@read_connection_1)
302
- end
294
+ it "should keep track of read connections that can't be reconnected for a set period" do
295
+ @pool_connection.available_read_connections.should include(@read_connection_1)
296
+ @pool_connection.suppress_read_connection(@read_connection_1, 30)
297
+ @pool_connection.available_read_connections.should_not include(@read_connection_1)
298
+ end
303
299
 
304
- it "should return dead connections to the pool after the timeout has expired" do
305
- @pool_connection.available_read_connections.should include(@read_connection_1)
306
- @pool_connection.suppress_read_connection(@read_connection_1, 0.2)
307
- @pool_connection.available_read_connections.should_not include(@read_connection_1)
308
- sleep(0.3)
309
- @pool_connection.available_read_connections.should include(@read_connection_1)
310
- end
300
+ it "should return dead connections to the pool after the timeout has expired" do
301
+ @pool_connection.available_read_connections.should include(@read_connection_1)
302
+ @pool_connection.suppress_read_connection(@read_connection_1, 0.2)
303
+ @pool_connection.available_read_connections.should_not include(@read_connection_1)
304
+ sleep(0.3)
305
+ @pool_connection.available_read_connections.should include(@read_connection_1)
306
+ end
311
307
 
312
- it "should not return a connection to the pool until it can be reconnected" do
313
- @pool_connection.available_read_connections.should include(@read_connection_1)
314
- @pool_connection.suppress_read_connection(@read_connection_1, 0.2)
315
- @pool_connection.available_read_connections.should_not include(@read_connection_1)
316
- sleep(0.3)
317
- @read_connection_1.should_receive(:reconnect!)
318
- @read_connection_1.should_receive(:active?).and_return(false)
319
- @pool_connection.available_read_connections.should_not include(@read_connection_1)
320
- end
308
+ it "should not return a connection to the pool until it can be reconnected" do
309
+ @pool_connection.available_read_connections.should include(@read_connection_1)
310
+ @pool_connection.suppress_read_connection(@read_connection_1, 0.2)
311
+ @pool_connection.available_read_connections.should_not include(@read_connection_1)
312
+ sleep(0.3)
313
+ @read_connection_1.should_receive(:reconnect!)
314
+ @read_connection_1.should_receive(:active?).and_return(false)
315
+ @pool_connection.available_read_connections.should_not include(@read_connection_1)
316
+ end
321
317
 
322
- it "should try all connections again if none of them can be reconnected" do
323
- stack = @pool_connection.instance_variable_get(:@available_read_connections)
318
+ it "should try all connections again if none of them can be reconnected" do
319
+ stack = @pool_connection.instance_variable_get(:@available_read_connections)
324
320
 
325
- available = @pool_connection.available_read_connections
326
- available.should include(@read_connection_1)
327
- available.should include(@read_connection_2)
328
- available.should include(@master_connection)
329
- stack.size.should == 1
321
+ available = @pool_connection.available_read_connections
322
+ available.should include(@read_connection_1)
323
+ available.should include(@read_connection_2)
324
+ available.should include(@master_connection)
325
+ stack.size.should == 1
330
326
 
331
- @pool_connection.suppress_read_connection(@read_connection_1, 30)
332
- available = @pool_connection.available_read_connections
333
- available.should_not include(@read_connection_1)
334
- available.should include(@read_connection_2)
335
- available.should include(@master_connection)
336
- stack.size.should == 2
327
+ @pool_connection.suppress_read_connection(@read_connection_1, 30)
328
+ available = @pool_connection.available_read_connections
329
+ available.should_not include(@read_connection_1)
330
+ available.should include(@read_connection_2)
331
+ available.should include(@master_connection)
332
+ stack.size.should == 2
337
333
 
338
- @pool_connection.suppress_read_connection(@master_connection, 30)
339
- available = @pool_connection.available_read_connections
340
- available.should_not include(@read_connection_1)
341
- available.should include(@read_connection_2)
342
- available.should_not include(@master_connection)
343
- stack.size.should == 3
344
-
345
- @pool_connection.suppress_read_connection(@read_connection_2, 30)
346
- available = @pool_connection.available_read_connections
347
- available.should include(@read_connection_1)
348
- available.should include(@read_connection_2)
349
- available.should include(@master_connection)
350
- stack.size.should == 1
351
- end
352
-
353
- it "should not try to suppress a read connection that wasn't available in the read pool" do
354
- stack = @pool_connection.instance_variable_get(:@available_read_connections)
355
- stack.size.should == 1
356
- @pool_connection.suppress_read_connection(@read_connection_1, 30)
357
- stack.size.should == 2
358
- @pool_connection.suppress_read_connection(@read_connection_1, 30)
359
- stack.size.should == 2
360
- end
334
+ @pool_connection.suppress_read_connection(@master_connection, 30)
335
+ available = @pool_connection.available_read_connections
336
+ available.should_not include(@read_connection_1)
337
+ available.should include(@read_connection_2)
338
+ available.should_not include(@master_connection)
339
+ stack.size.should == 3
361
340
 
362
- end
363
-
364
- describe "Reload extensions" do
365
- before(:all) do
366
- SeamlessDatabasePool::Test.create_tables
367
- @record = SeamlessDatabasePool::Test::Model.create(:name => 'test')
368
- @thing = SeamlessDatabasePool::Test::Thing.create(:name => 'thing', :model_id => @record.id)
369
- end
370
-
371
- after(:all) do
372
- SeamlessDatabasePool::Test.drop_tables
373
- end
341
+ @pool_connection.suppress_read_connection(@read_connection_2, 30)
342
+ available = @pool_connection.available_read_connections
343
+ available.should include(@read_connection_1)
344
+ available.should include(@read_connection_2)
345
+ available.should include(@master_connection)
346
+ stack.size.should == 1
347
+ end
374
348
 
375
- it "should force the master connection on reload" do
376
- SeamlessDatabasePool.should_receive(:use_master_connection).and_yield
377
- @record.should_receive(:reload_without_seamless_database_pool).with(:options)
378
- @record.reload(:options)
349
+ it "should not try to suppress a read connection that wasn't available in the read pool" do
350
+ stack = @pool_connection.instance_variable_get(:@available_read_connections)
351
+ stack.size.should == 1
352
+ @pool_connection.suppress_read_connection(@read_connection_1, 30)
353
+ stack.size.should == 2
354
+ @pool_connection.suppress_read_connection(@read_connection_1, 30)
355
+ stack.size.should == 2
356
+ end
379
357
  end
380
358
  end
data/spec/spec_helper.rb CHANGED
@@ -1,12 +1,13 @@
1
1
  require 'rubygems'
2
2
 
3
- active_record_version = ENV["ACTIVE_RECORD_VERSION"] || [">= 2.2.2", "< 3.0"]
3
+ active_record_version = ENV["ACTIVE_RECORD_VERSION"] || [">= 2.2.2"]
4
4
  active_record_version = [active_record_version] unless active_record_version.is_a?(Array)
5
5
  gem 'activerecord', *active_record_version
6
6
 
7
- require 'spec'
8
7
  require 'active_record'
9
8
  puts "Testing Against ActiveRecord #{ActiveRecord::VERSION::STRING}" if defined?(ActiveRecord::VERSION)
10
9
 
11
10
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'seamless_database_pool'))
12
- require File.expand_path(File.join(File.dirname(__FILE__), 'test_models'))
11
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_model'))
12
+
13
+ $LOAD_PATH << File.expand_path("../test_adapter", __FILE__)
@@ -0,0 +1,51 @@
1
+ module ActiveRecord
2
+ class Base
3
+ def self.read_only_connection (config)
4
+ real_adapter = config.delete("real_adapter")
5
+ connection = send("#{real_adapter}_connection", config.merge("adapter" => real_adapter))
6
+ ConnectionAdapters::ReadOnlyAdapter.new(connection)
7
+ end
8
+ end
9
+
10
+ module ConnectionAdapters
11
+ class ReadOnlyAdapter < AbstractAdapter
12
+ %w(select_one select_all select_value select_values select select_rows execute tables columns).each do |read_method|
13
+ class_eval <<-EOS
14
+ def #{read_method} (*args, &block)
15
+ raise "Not Connected" unless @connected
16
+ result = @connection.send(:#{read_method}, *args, &block)
17
+ def result.read_only?
18
+ true
19
+ end
20
+ result
21
+ end
22
+ EOS
23
+
24
+ %w(update insert delete reload create_table drop_table add_index remove_index transaction).each do |write_method|
25
+ class_eval <<-EOS
26
+ def #{write_method} (*args, &block)
27
+ raise NotImplementedError.new("Master method '#{write_method}' called on read only connection")
28
+ end
29
+ EOS
30
+ end
31
+ end
32
+
33
+ def initialize (connection)
34
+ @connection = connection
35
+ @connected = true
36
+ end
37
+
38
+ def reconnect!
39
+ @connected = true
40
+ end
41
+
42
+ def disconnect!
43
+ @connected = false
44
+ end
45
+
46
+ def active?
47
+ @connected
48
+ end
49
+ end
50
+ end
51
+ end