seamless_database_pool 1.0.5 → 1.0.6

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.
@@ -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