epugh-sequel 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. data/README.rdoc +652 -0
  2. data/VERSION.yml +4 -0
  3. data/bin/sequel +104 -0
  4. data/lib/sequel.rb +1 -0
  5. data/lib/sequel/adapters/ado.rb +85 -0
  6. data/lib/sequel/adapters/db2.rb +132 -0
  7. data/lib/sequel/adapters/dbi.rb +101 -0
  8. data/lib/sequel/adapters/do.rb +197 -0
  9. data/lib/sequel/adapters/do/mysql.rb +38 -0
  10. data/lib/sequel/adapters/do/postgres.rb +92 -0
  11. data/lib/sequel/adapters/do/sqlite.rb +31 -0
  12. data/lib/sequel/adapters/firebird.rb +307 -0
  13. data/lib/sequel/adapters/informix.rb +75 -0
  14. data/lib/sequel/adapters/jdbc.rb +485 -0
  15. data/lib/sequel/adapters/jdbc/h2.rb +62 -0
  16. data/lib/sequel/adapters/jdbc/mysql.rb +56 -0
  17. data/lib/sequel/adapters/jdbc/oracle.rb +23 -0
  18. data/lib/sequel/adapters/jdbc/postgresql.rb +101 -0
  19. data/lib/sequel/adapters/jdbc/sqlite.rb +43 -0
  20. data/lib/sequel/adapters/mysql.rb +370 -0
  21. data/lib/sequel/adapters/odbc.rb +184 -0
  22. data/lib/sequel/adapters/openbase.rb +57 -0
  23. data/lib/sequel/adapters/oracle.rb +140 -0
  24. data/lib/sequel/adapters/postgres.rb +453 -0
  25. data/lib/sequel/adapters/shared/mssql.rb +93 -0
  26. data/lib/sequel/adapters/shared/mysql.rb +341 -0
  27. data/lib/sequel/adapters/shared/oracle.rb +62 -0
  28. data/lib/sequel/adapters/shared/postgres.rb +743 -0
  29. data/lib/sequel/adapters/shared/progress.rb +34 -0
  30. data/lib/sequel/adapters/shared/sqlite.rb +263 -0
  31. data/lib/sequel/adapters/sqlite.rb +243 -0
  32. data/lib/sequel/adapters/utils/date_format.rb +21 -0
  33. data/lib/sequel/adapters/utils/stored_procedures.rb +75 -0
  34. data/lib/sequel/adapters/utils/unsupported.rb +62 -0
  35. data/lib/sequel/connection_pool.rb +258 -0
  36. data/lib/sequel/core.rb +204 -0
  37. data/lib/sequel/core_sql.rb +185 -0
  38. data/lib/sequel/database.rb +687 -0
  39. data/lib/sequel/database/schema_generator.rb +324 -0
  40. data/lib/sequel/database/schema_methods.rb +164 -0
  41. data/lib/sequel/database/schema_sql.rb +324 -0
  42. data/lib/sequel/dataset.rb +422 -0
  43. data/lib/sequel/dataset/convenience.rb +237 -0
  44. data/lib/sequel/dataset/prepared_statements.rb +220 -0
  45. data/lib/sequel/dataset/sql.rb +1105 -0
  46. data/lib/sequel/deprecated.rb +529 -0
  47. data/lib/sequel/exceptions.rb +44 -0
  48. data/lib/sequel/extensions/blank.rb +42 -0
  49. data/lib/sequel/extensions/inflector.rb +288 -0
  50. data/lib/sequel/extensions/pagination.rb +96 -0
  51. data/lib/sequel/extensions/pretty_table.rb +78 -0
  52. data/lib/sequel/extensions/query.rb +48 -0
  53. data/lib/sequel/extensions/string_date_time.rb +47 -0
  54. data/lib/sequel/metaprogramming.rb +44 -0
  55. data/lib/sequel/migration.rb +212 -0
  56. data/lib/sequel/model.rb +142 -0
  57. data/lib/sequel/model/association_reflection.rb +263 -0
  58. data/lib/sequel/model/associations.rb +1024 -0
  59. data/lib/sequel/model/base.rb +911 -0
  60. data/lib/sequel/model/deprecated.rb +188 -0
  61. data/lib/sequel/model/deprecated_hooks.rb +103 -0
  62. data/lib/sequel/model/deprecated_inflector.rb +335 -0
  63. data/lib/sequel/model/deprecated_validations.rb +384 -0
  64. data/lib/sequel/model/errors.rb +37 -0
  65. data/lib/sequel/model/exceptions.rb +7 -0
  66. data/lib/sequel/model/inflections.rb +230 -0
  67. data/lib/sequel/model/plugins.rb +74 -0
  68. data/lib/sequel/object_graph.rb +230 -0
  69. data/lib/sequel/plugins/caching.rb +122 -0
  70. data/lib/sequel/plugins/hook_class_methods.rb +122 -0
  71. data/lib/sequel/plugins/schema.rb +53 -0
  72. data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
  73. data/lib/sequel/plugins/validation_class_methods.rb +373 -0
  74. data/lib/sequel/sql.rb +854 -0
  75. data/lib/sequel/version.rb +11 -0
  76. data/lib/sequel_core.rb +1 -0
  77. data/lib/sequel_model.rb +1 -0
  78. data/spec/adapters/ado_spec.rb +46 -0
  79. data/spec/adapters/firebird_spec.rb +376 -0
  80. data/spec/adapters/informix_spec.rb +96 -0
  81. data/spec/adapters/mysql_spec.rb +875 -0
  82. data/spec/adapters/oracle_spec.rb +272 -0
  83. data/spec/adapters/postgres_spec.rb +692 -0
  84. data/spec/adapters/spec_helper.rb +10 -0
  85. data/spec/adapters/sqlite_spec.rb +550 -0
  86. data/spec/core/connection_pool_spec.rb +526 -0
  87. data/spec/core/core_ext_spec.rb +156 -0
  88. data/spec/core/core_sql_spec.rb +528 -0
  89. data/spec/core/database_spec.rb +1214 -0
  90. data/spec/core/dataset_spec.rb +3513 -0
  91. data/spec/core/expression_filters_spec.rb +363 -0
  92. data/spec/core/migration_spec.rb +261 -0
  93. data/spec/core/object_graph_spec.rb +280 -0
  94. data/spec/core/pretty_table_spec.rb +58 -0
  95. data/spec/core/schema_generator_spec.rb +167 -0
  96. data/spec/core/schema_spec.rb +778 -0
  97. data/spec/core/spec_helper.rb +82 -0
  98. data/spec/core/version_spec.rb +7 -0
  99. data/spec/extensions/blank_spec.rb +67 -0
  100. data/spec/extensions/caching_spec.rb +201 -0
  101. data/spec/extensions/hook_class_methods_spec.rb +470 -0
  102. data/spec/extensions/inflector_spec.rb +122 -0
  103. data/spec/extensions/pagination_spec.rb +99 -0
  104. data/spec/extensions/pretty_table_spec.rb +91 -0
  105. data/spec/extensions/query_spec.rb +85 -0
  106. data/spec/extensions/schema_spec.rb +111 -0
  107. data/spec/extensions/single_table_inheritance_spec.rb +53 -0
  108. data/spec/extensions/spec_helper.rb +90 -0
  109. data/spec/extensions/string_date_time_spec.rb +93 -0
  110. data/spec/extensions/validation_class_methods_spec.rb +1054 -0
  111. data/spec/integration/dataset_test.rb +160 -0
  112. data/spec/integration/eager_loader_test.rb +683 -0
  113. data/spec/integration/prepared_statement_test.rb +130 -0
  114. data/spec/integration/schema_test.rb +183 -0
  115. data/spec/integration/spec_helper.rb +75 -0
  116. data/spec/integration/type_test.rb +96 -0
  117. data/spec/model/association_reflection_spec.rb +93 -0
  118. data/spec/model/associations_spec.rb +1780 -0
  119. data/spec/model/base_spec.rb +494 -0
  120. data/spec/model/caching_spec.rb +217 -0
  121. data/spec/model/dataset_methods_spec.rb +78 -0
  122. data/spec/model/eager_loading_spec.rb +1165 -0
  123. data/spec/model/hooks_spec.rb +472 -0
  124. data/spec/model/inflector_spec.rb +126 -0
  125. data/spec/model/model_spec.rb +588 -0
  126. data/spec/model/plugins_spec.rb +142 -0
  127. data/spec/model/record_spec.rb +1243 -0
  128. data/spec/model/schema_spec.rb +92 -0
  129. data/spec/model/spec_helper.rb +124 -0
  130. data/spec/model/validations_spec.rb +1080 -0
  131. data/spec/rcov.opts +6 -0
  132. data/spec/spec.opts +0 -0
  133. data/spec/spec_config.rb.example +10 -0
  134. metadata +202 -0
@@ -0,0 +1,526 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+ CONNECTION_POOL_DEFAULTS = {:pool_timeout=>5, :pool_sleep_time=>0.001,
3
+ :pool_reuse_connections=>:allow, :pool_convert_exceptions=>true, :max_connections=>4}
4
+
5
+ context "An empty ConnectionPool" do
6
+ setup do
7
+ @cpool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS)
8
+ end
9
+
10
+ specify "should have no available connections" do
11
+ @cpool.available_connections.should == []
12
+ end
13
+
14
+ specify "should have no allocated connections" do
15
+ @cpool.allocated.should == {}
16
+ end
17
+
18
+ specify "should have a created_count of zero" do
19
+ @cpool.created_count.should == 0
20
+ end
21
+ end
22
+
23
+ context "A connection pool handling connections" do
24
+ setup do
25
+ @max_size = 2
26
+ @cpool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:disconnection_proc=>proc{|c| @max_size=3}, :max_connections=>@max_size)) {:got_connection}
27
+ end
28
+
29
+ specify "#hold should increment #created_count" do
30
+ @cpool.hold do
31
+ @cpool.created_count.should == 1
32
+ @cpool.hold {@cpool.hold {@cpool.created_count.should == 1}}
33
+ Thread.new{@cpool.hold {@cpool.created_count.should == 2}}.join
34
+ end
35
+ end
36
+
37
+ specify "#hold should add the connection to the #allocated array" do
38
+ @cpool.hold do
39
+ @cpool.allocated.size.should == 1
40
+
41
+ @cpool.allocated.should == {Thread.current=>:got_connection}
42
+ end
43
+ end
44
+
45
+ specify "#hold should yield a new connection" do
46
+ @cpool.hold {|conn| conn.should == :got_connection}
47
+ end
48
+
49
+ specify "a connection should be de-allocated after it has been used in #hold" do
50
+ @cpool.hold {}
51
+ @cpool.allocated.size.should == 0
52
+ end
53
+
54
+ specify "#hold should return the value of its block" do
55
+ @cpool.hold {:block_return}.should == :block_return
56
+ end
57
+
58
+ specify "#make_new should not make more than max_size connections" do
59
+ @cpool.send(:make_new, :default).should == :got_connection
60
+ @cpool.send(:make_new, :default).should == :got_connection
61
+ @cpool.send(:make_new, :default).should == nil
62
+ @cpool.created_count.should == 2
63
+ end
64
+
65
+ specify ":disconnection_proc option should set the disconnection proc to use" do
66
+ @max_size.should == 2
67
+ proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
68
+ @max_size.should == 3
69
+ end
70
+
71
+ specify "#disconnection_proc= should set the disconnection proc to use" do
72
+ a = 1
73
+ @cpool.disconnection_proc = proc{|c| a += 1}
74
+ proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
75
+ a.should == 2
76
+ end
77
+
78
+ specify "#hold should remove the connection if a DatabaseDisconnectError is raised" do
79
+ @cpool.created_count.should == 0
80
+ @cpool.hold{Thread.new{@cpool.hold{}}; sleep 0.01}
81
+ @cpool.created_count.should == 2
82
+ proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
83
+ @cpool.created_count.should == 1
84
+ proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
85
+ @cpool.created_count.should == 0
86
+ proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
87
+ @cpool.created_count.should == 0
88
+ end
89
+ end
90
+
91
+ context "A connection pool handling connection errors" do
92
+ specify "#hold should raise a Sequel::DatabaseConnectionError if an exception is raised by the connection_proc" do
93
+ cpool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS){raise Interrupt}
94
+ proc{cpool.hold{:block_return}}.should raise_error(Sequel::DatabaseConnectionError)
95
+ cpool.created_count.should == 0
96
+ end
97
+
98
+ specify "#hold should raise a Sequel::DatabaseConnectionError if nil is returned by the connection_proc" do
99
+ cpool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS){nil}
100
+ proc{cpool.hold{:block_return}}.should raise_error(Sequel::DatabaseConnectionError)
101
+ cpool.created_count.should == 0
102
+ end
103
+ end
104
+
105
+ class DummyConnection
106
+ @@value = 0
107
+ def initialize
108
+ @@value += 1
109
+ end
110
+
111
+ def value
112
+ @@value
113
+ end
114
+ end
115
+
116
+ context "ConnectionPool#hold" do
117
+ setup do
118
+ @pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS) {DummyConnection.new}
119
+ end
120
+
121
+ specify "should pass the result of the connection maker proc to the supplied block" do
122
+ res = nil
123
+ @pool.hold {|c| res = c}
124
+ res.should be_a_kind_of(DummyConnection)
125
+ res.value.should == 1
126
+ @pool.hold {|c| res = c}
127
+ res.should be_a_kind_of(DummyConnection)
128
+ res.value.should == 1 # the connection maker is invoked only once
129
+ end
130
+
131
+ specify "should be re-entrant by the same thread" do
132
+ cc = nil
133
+ @pool.hold {|c| @pool.hold {|c| @pool.hold {|c| cc = c}}}
134
+ cc.should be_a_kind_of(DummyConnection)
135
+ end
136
+
137
+ specify "should catch exceptions and reraise them" do
138
+ proc {@pool.hold {|c| c.foobar}}.should raise_error(NoMethodError)
139
+ end
140
+
141
+ specify "should handle Exception errors (normally not caught by rescue)" do
142
+ err = nil
143
+ begin
144
+ @pool.hold {raise Exception}
145
+ rescue => e
146
+ err = e
147
+ end
148
+ err.should be_a_kind_of(RuntimeError)
149
+ end
150
+ end
151
+
152
+ context "ConnectionPool#connection_proc" do
153
+ setup do
154
+ @pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS)
155
+ end
156
+
157
+ specify "should be nil if no block is supplied to the pool" do
158
+ @pool.connection_proc.should be_nil
159
+ proc {@pool.hold {}}.should raise_error
160
+ end
161
+
162
+ specify "should be mutable" do
163
+ @pool.connection_proc = proc {'herro'}
164
+ res = nil
165
+ proc {@pool.hold {|c| res = c}}.should_not raise_error
166
+ res.should == 'herro'
167
+ end
168
+ end
169
+
170
+ context "A connection pool with a max size of 1" do
171
+ setup do
172
+ @invoked_count = 0
173
+ @pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>1)) {@invoked_count += 1; 'herro'}
174
+ end
175
+
176
+ specify "should let only one thread access the connection at any time" do
177
+ cc,c1, c2 = nil
178
+
179
+ t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup; while c == 'herro';sleep 0.01;end}}
180
+ sleep 0.02
181
+ cc.should == 'herro'
182
+ c1.should == 'herro'
183
+
184
+ t2 = Thread.new {@pool.hold {|c| c2 = c.dup; while c == 'hello';sleep 0.01;end}}
185
+ sleep 0.02
186
+
187
+ # connection held by t1
188
+ t1.should be_alive
189
+ t2.should be_alive
190
+
191
+ cc.should == 'herro'
192
+ c1.should == 'herro'
193
+ c2.should be_nil
194
+
195
+ @pool.available_connections.should be_empty
196
+ @pool.allocated.should == {t1=>cc}
197
+
198
+ cc.gsub!('rr', 'll')
199
+ sleep 0.05
200
+
201
+ # connection held by t2
202
+ t1.should_not be_alive
203
+ t2.should be_alive
204
+
205
+ c2.should == 'hello'
206
+
207
+ @pool.available_connections.should be_empty
208
+ @pool.allocated.should == {t2=>cc}
209
+
210
+ cc.gsub!('ll', 'rr')
211
+ sleep 0.05
212
+
213
+ #connection released
214
+ t2.should_not be_alive
215
+
216
+ cc.should == 'herro'
217
+
218
+ @invoked_count.should == 1
219
+ @pool.size.should == 1
220
+ @pool.available_connections.should == [cc]
221
+ @pool.allocated.should be_empty
222
+ end
223
+
224
+ specify "should let the same thread reenter #hold" do
225
+ c1, c2, c3 = nil
226
+ @pool.hold do |c|
227
+ c1 = c
228
+ @pool.hold do |c|
229
+ c2 = c
230
+ @pool.hold do |c|
231
+ c3 = c
232
+ end
233
+ end
234
+ end
235
+ c1.should == 'herro'
236
+ c2.should == 'herro'
237
+ c3.should == 'herro'
238
+
239
+ @invoked_count.should == 1
240
+ @pool.size.should == 1
241
+ @pool.available_connections.size.should == 1
242
+ @pool.allocated.should be_empty
243
+ end
244
+ end
245
+
246
+ context "A connection pool with a max size of 5" do
247
+ setup do
248
+ @invoked_count = 0
249
+ @pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {@invoked_count += 1}
250
+ end
251
+
252
+ specify "should let five threads simultaneously access separate connections" do
253
+ cc = {}
254
+ threads = []
255
+ stop = nil
256
+
257
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.01;end}}; sleep 0.01}
258
+ sleep 0.02
259
+ threads.each {|t| t.should be_alive}
260
+ cc.size.should == 5
261
+ @invoked_count.should == 5
262
+ @pool.size.should == 5
263
+ @pool.available_connections.should be_empty
264
+ i = 0
265
+ h = {}
266
+ threads.each{|t| h[t] = (i+=1)}
267
+ @pool.allocated.should == h
268
+
269
+ threads[0].raise "your'e dead"
270
+ sleep 0.01
271
+ threads[3].raise "your'e dead too"
272
+
273
+ sleep 0.01
274
+
275
+ @pool.available_connections.should == [1, 4]
276
+ @pool.allocated.should == {threads[1]=>2, threads[2]=>3, threads[4]=>5}
277
+
278
+ stop = true
279
+ sleep 0.02
280
+
281
+ @pool.available_connections.size.should == 5
282
+ @pool.allocated.should be_empty
283
+ end
284
+
285
+ specify "should block threads until a connection becomes available" do
286
+ cc = {}
287
+ threads = []
288
+ stop = nil
289
+
290
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.01;end}}; sleep 0.01}
291
+ sleep 0.02
292
+ threads.each {|t| t.should be_alive}
293
+ @pool.available_connections.should be_empty
294
+
295
+ 3.times {|i| threads << Thread.new {@pool.hold {|c| cc[i + 5] = c}}}
296
+
297
+ sleep 0.02
298
+ threads[5].should be_alive
299
+ threads[6].should be_alive
300
+ threads[7].should be_alive
301
+ cc.size.should == 5
302
+ cc[5].should be_nil
303
+ cc[6].should be_nil
304
+ cc[7].should be_nil
305
+
306
+ stop = true
307
+ sleep 0.05
308
+
309
+ threads.each {|t| t.should_not be_alive}
310
+
311
+ @pool.size.should == 5
312
+ @invoked_count.should == 5
313
+ @pool.available_connections.size.should == 5
314
+ @pool.allocated.should be_empty
315
+ end
316
+ end
317
+
318
+ context "ConnectionPool#disconnect" do
319
+ setup do
320
+ @count = 0
321
+ @pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {{:id => @count += 1}}
322
+ end
323
+
324
+ specify "should invoke the given block for each available connection" do
325
+ threads = []
326
+ stop = nil
327
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.01;end}}; sleep 0.01}
328
+ while @pool.size < 5
329
+ sleep 0.02
330
+ end
331
+ stop = true
332
+ sleep 0.1
333
+ threads.each {|t| t.join}
334
+
335
+ @pool.size.should == 5
336
+ @pool.available_connections.size.should == 5
337
+ @pool.available_connections.each {|c| c[:id].should_not be_nil}
338
+ conns = []
339
+ @pool.disconnect {|c| conns << c}
340
+ conns.size.should == 5
341
+ end
342
+
343
+ specify "should remove all available connections" do
344
+ threads = []
345
+ stop = nil
346
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.01;end}}; sleep 0.01}
347
+ while @pool.size < 5
348
+ sleep 0.02
349
+ end
350
+ stop = true
351
+ sleep 0.1
352
+ threads.each {|t| t.join}
353
+
354
+ @pool.size.should == 5
355
+ @pool.disconnect
356
+ @pool.size.should == 0
357
+ end
358
+
359
+ specify "should not touch connections in use" do
360
+ threads = []
361
+ stop = nil
362
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.01;end}}; sleep 0.01}
363
+ while @pool.size < 5
364
+ sleep 0.02
365
+ end
366
+ stop = true
367
+ sleep 0.1
368
+ threads.each {|t| t.join}
369
+
370
+ @pool.size.should == 5
371
+
372
+ @pool.hold do |conn|
373
+ @pool.available_connections.size.should == 4
374
+ @pool.available_connections.each {|c| c.should_not be(conn)}
375
+ conns = []
376
+ @pool.disconnect {|c| conns << c}
377
+ conns.size.should == 4
378
+ end
379
+ @pool.size.should == 1
380
+ end
381
+ end
382
+
383
+ context "A connection pool with multiple servers" do
384
+ setup do
385
+ @invoked_counts = Hash.new(0)
386
+ @pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:servers=>{:read_only=>{}})){|server| "#{server}#{@invoked_counts[server] += 1}"}
387
+ end
388
+
389
+ specify "should use the :default server by default" do
390
+ @pool.size.should == 0
391
+ @pool.hold do |c|
392
+ c.should == "default1"
393
+ @pool.allocated.should == {Thread.current=>"default1"}
394
+ end
395
+ @pool.available_connections.should == ["default1"]
396
+ @pool.size.should == 1
397
+ @invoked_counts.should == {:default=>1}
398
+ end
399
+
400
+ specify "should use the requested server if server is given" do
401
+ @pool.size(:read_only).should == 0
402
+ @pool.hold(:read_only) do |c|
403
+ c.should == "read_only1"
404
+ @pool.allocated(:read_only).should == {Thread.current=>"read_only1"}
405
+ end
406
+ @pool.available_connections(:read_only).should == ["read_only1"]
407
+ @pool.size(:read_only).should == 1
408
+ @invoked_counts.should == {:read_only=>1}
409
+ end
410
+
411
+ specify "#hold should only yield connections for the server requested" do
412
+ @pool.hold(:read_only) do |c|
413
+ c.should == "read_only1"
414
+ @pool.allocated(:read_only).should == {Thread.current=>"read_only1"}
415
+ @pool.hold do |d|
416
+ d.should == "default1"
417
+ @pool.hold do |e|
418
+ e.should == d
419
+ @pool.hold(:read_only){|b| b.should == c}
420
+ end
421
+ @pool.allocated.should == {Thread.current=>"default1"}
422
+ end
423
+ end
424
+ @invoked_counts.should == {:read_only=>1, :default=>1}
425
+ end
426
+
427
+ specify "#disconnect should disconnect from all servers" do
428
+ @pool.hold(:read_only){}
429
+ @pool.hold{}
430
+ conns = []
431
+ @pool.size.should == 1
432
+ @pool.size(:read_only).should == 1
433
+ @pool.disconnect{|c| conns << c}
434
+ conns.sort.should == %w'default1 read_only1'
435
+ @pool.size.should == 0
436
+ @pool.size(:read_only).should == 0
437
+ @pool.hold(:read_only){|c| c.should == 'read_only2'}
438
+ @pool.hold{|c| c.should == 'default2'}
439
+ end
440
+ end
441
+
442
+ context "SingleThreadedPool" do
443
+ setup do
444
+ @pool = Sequel::SingleThreadedPool.new(CONNECTION_POOL_DEFAULTS){1234}
445
+ end
446
+
447
+ specify "should provide a #hold method" do
448
+ conn = nil
449
+ @pool.hold {|c| conn = c}
450
+ conn.should == 1234
451
+ end
452
+
453
+ specify "should provide a #disconnect method" do
454
+ @pool.hold {|c|}
455
+ @pool.conn.should == 1234
456
+ conn = nil
457
+ @pool.disconnect {|c| conn = c}
458
+ conn.should == 1234
459
+ @pool.conn.should be_nil
460
+ end
461
+ end
462
+
463
+ context "A single threaded pool with multiple servers" do
464
+ setup do
465
+ @max_size=2
466
+ @pool = Sequel::SingleThreadedPool.new(CONNECTION_POOL_DEFAULTS.merge(:disconnection_proc=>proc{|c| @max_size=3}, :servers=>{:read_only=>{}})){|server| server}
467
+ end
468
+
469
+ specify "should use the :default server by default" do
470
+ @pool.hold{|c| c.should == :default}
471
+ @pool.conn.should == :default
472
+ end
473
+
474
+ specify "should use the requested server if server is given" do
475
+ @pool.hold(:read_only){|c| c.should == :read_only}
476
+ @pool.conn(:read_only).should == :read_only
477
+ end
478
+
479
+ specify "#hold should only yield connections for the server requested" do
480
+ @pool.hold(:read_only) do |c|
481
+ c.should == :read_only
482
+ @pool.hold do |d|
483
+ d.should == :default
484
+ @pool.hold do |e|
485
+ e.should == d
486
+ @pool.hold(:read_only){|b| b.should == c}
487
+ end
488
+ end
489
+ end
490
+ @pool.conn.should == :default
491
+ @pool.conn(:read_only).should == :read_only
492
+ end
493
+
494
+ specify "#disconnect should disconnect from all servers" do
495
+ @pool.hold(:read_only){}
496
+ @pool.hold{}
497
+ conns = []
498
+ @pool.conn.should == :default
499
+ @pool.conn(:read_only).should == :read_only
500
+ @pool.disconnect{|c| conns << c}
501
+ conns.sort_by{|x| x.to_s}.should == [:default, :read_only]
502
+ @pool.conn.should == nil
503
+ @pool.conn(:read_only).should == nil
504
+ end
505
+
506
+ specify ":disconnection_proc option should set the disconnection proc to use" do
507
+ @max_size.should == 2
508
+ proc{@pool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
509
+ @max_size.should == 3
510
+ end
511
+
512
+ specify "#disconnection_proc= should set the disconnection proc to use" do
513
+ a = 1
514
+ @pool.disconnection_proc = proc{|c| a += 1}
515
+ proc{@pool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
516
+ a.should == 2
517
+ end
518
+
519
+ specify "#hold should remove the connection if a DatabaseDisconnectError is raised" do
520
+ @pool.instance_variable_get(:@conns).length.should == 0
521
+ @pool.hold{}
522
+ @pool.instance_variable_get(:@conns).length.should == 1
523
+ proc{@pool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
524
+ @pool.instance_variable_get(:@conns).length.should == 0
525
+ end
526
+ end