sequel 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/CHANGELOG +1551 -4
  2. data/README +306 -19
  3. data/Rakefile +84 -56
  4. data/bin/sequel +106 -0
  5. data/doc/cheat_sheet.rdoc +225 -0
  6. data/doc/dataset_filtering.rdoc +182 -0
  7. data/lib/sequel_core.rb +136 -0
  8. data/lib/sequel_core/adapters/adapter_skeleton.rb +54 -0
  9. data/lib/sequel_core/adapters/ado.rb +80 -0
  10. data/lib/sequel_core/adapters/db2.rb +148 -0
  11. data/lib/sequel_core/adapters/dbi.rb +117 -0
  12. data/lib/sequel_core/adapters/informix.rb +78 -0
  13. data/lib/sequel_core/adapters/jdbc.rb +186 -0
  14. data/lib/sequel_core/adapters/jdbc/mysql.rb +55 -0
  15. data/lib/sequel_core/adapters/jdbc/postgresql.rb +66 -0
  16. data/lib/sequel_core/adapters/jdbc/sqlite.rb +47 -0
  17. data/lib/sequel_core/adapters/mysql.rb +231 -0
  18. data/lib/sequel_core/adapters/odbc.rb +155 -0
  19. data/lib/sequel_core/adapters/odbc_mssql.rb +106 -0
  20. data/lib/sequel_core/adapters/openbase.rb +64 -0
  21. data/lib/sequel_core/adapters/oracle.rb +170 -0
  22. data/lib/sequel_core/adapters/postgres.rb +199 -0
  23. data/lib/sequel_core/adapters/shared/mysql.rb +275 -0
  24. data/lib/sequel_core/adapters/shared/postgres.rb +351 -0
  25. data/lib/sequel_core/adapters/shared/sqlite.rb +146 -0
  26. data/lib/sequel_core/adapters/sqlite.rb +138 -0
  27. data/lib/sequel_core/connection_pool.rb +194 -0
  28. data/lib/sequel_core/core_ext.rb +203 -0
  29. data/lib/sequel_core/core_sql.rb +184 -0
  30. data/lib/sequel_core/database.rb +471 -0
  31. data/lib/sequel_core/database/schema.rb +156 -0
  32. data/lib/sequel_core/dataset.rb +457 -0
  33. data/lib/sequel_core/dataset/callback.rb +13 -0
  34. data/lib/sequel_core/dataset/convenience.rb +245 -0
  35. data/lib/sequel_core/dataset/pagination.rb +96 -0
  36. data/lib/sequel_core/dataset/query.rb +41 -0
  37. data/lib/sequel_core/dataset/schema.rb +15 -0
  38. data/lib/sequel_core/dataset/sql.rb +889 -0
  39. data/lib/sequel_core/deprecated.rb +26 -0
  40. data/lib/sequel_core/exceptions.rb +42 -0
  41. data/lib/sequel_core/migration.rb +187 -0
  42. data/lib/sequel_core/object_graph.rb +216 -0
  43. data/lib/sequel_core/pretty_table.rb +71 -0
  44. data/lib/sequel_core/schema.rb +2 -0
  45. data/lib/sequel_core/schema/generator.rb +239 -0
  46. data/lib/sequel_core/schema/sql.rb +325 -0
  47. data/lib/sequel_core/sql.rb +812 -0
  48. data/lib/sequel_model.rb +5 -1
  49. data/lib/sequel_model/association_reflection.rb +3 -8
  50. data/lib/sequel_model/base.rb +15 -10
  51. data/lib/sequel_model/inflector.rb +3 -5
  52. data/lib/sequel_model/plugins.rb +1 -1
  53. data/lib/sequel_model/record.rb +11 -3
  54. data/lib/sequel_model/schema.rb +4 -4
  55. data/lib/sequel_model/validations.rb +6 -1
  56. data/spec/adapters/ado_spec.rb +17 -0
  57. data/spec/adapters/informix_spec.rb +96 -0
  58. data/spec/adapters/mysql_spec.rb +764 -0
  59. data/spec/adapters/oracle_spec.rb +222 -0
  60. data/spec/adapters/postgres_spec.rb +441 -0
  61. data/spec/adapters/spec_helper.rb +7 -0
  62. data/spec/adapters/sqlite_spec.rb +400 -0
  63. data/spec/integration/dataset_test.rb +51 -0
  64. data/spec/integration/eager_loader_test.rb +702 -0
  65. data/spec/integration/schema_test.rb +102 -0
  66. data/spec/integration/spec_helper.rb +44 -0
  67. data/spec/integration/type_test.rb +43 -0
  68. data/spec/rcov.opts +2 -0
  69. data/spec/sequel_core/connection_pool_spec.rb +363 -0
  70. data/spec/sequel_core/core_ext_spec.rb +156 -0
  71. data/spec/sequel_core/core_sql_spec.rb +427 -0
  72. data/spec/sequel_core/database_spec.rb +964 -0
  73. data/spec/sequel_core/dataset_spec.rb +2977 -0
  74. data/spec/sequel_core/expression_filters_spec.rb +346 -0
  75. data/spec/sequel_core/migration_spec.rb +261 -0
  76. data/spec/sequel_core/object_graph_spec.rb +234 -0
  77. data/spec/sequel_core/pretty_table_spec.rb +58 -0
  78. data/spec/sequel_core/schema_generator_spec.rb +122 -0
  79. data/spec/sequel_core/schema_spec.rb +497 -0
  80. data/spec/sequel_core/spec_helper.rb +51 -0
  81. data/spec/{association_reflection_spec.rb → sequel_model/association_reflection_spec.rb} +6 -6
  82. data/spec/{associations_spec.rb → sequel_model/associations_spec.rb} +47 -18
  83. data/spec/{base_spec.rb → sequel_model/base_spec.rb} +2 -1
  84. data/spec/{caching_spec.rb → sequel_model/caching_spec.rb} +0 -0
  85. data/spec/{dataset_methods_spec.rb → sequel_model/dataset_methods_spec.rb} +13 -1
  86. data/spec/{eager_loading_spec.rb → sequel_model/eager_loading_spec.rb} +75 -14
  87. data/spec/{hooks_spec.rb → sequel_model/hooks_spec.rb} +4 -4
  88. data/spec/sequel_model/inflector_spec.rb +119 -0
  89. data/spec/{model_spec.rb → sequel_model/model_spec.rb} +30 -11
  90. data/spec/{plugins_spec.rb → sequel_model/plugins_spec.rb} +0 -0
  91. data/spec/{record_spec.rb → sequel_model/record_spec.rb} +47 -6
  92. data/spec/{schema_spec.rb → sequel_model/schema_spec.rb} +18 -4
  93. data/spec/{spec_helper.rb → sequel_model/spec_helper.rb} +3 -2
  94. data/spec/{validations_spec.rb → sequel_model/validations_spec.rb} +37 -17
  95. data/spec/spec_config.rb +9 -0
  96. data/spec/spec_config.rb.example +10 -0
  97. metadata +110 -37
  98. data/spec/inflector_spec.rb +0 -34
@@ -0,0 +1,102 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper.rb')
2
+
3
+ describe "Database schema parser" do
4
+ before do
5
+ INTEGRATION_DB.create_table!(:items){integer :number}
6
+ clear_sqls
7
+ end
8
+ after do
9
+ INTEGRATION_DB.drop_table(:items) if INTEGRATION_DB.table_exists?(:items)
10
+ end
11
+
12
+ specify "should be a hash with table_names as symbols" do
13
+ schema = INTEGRATION_DB.schema(nil, :reload=>true)
14
+ schema.should be_a_kind_of(Hash)
15
+ schema.should include(:items)
16
+ end
17
+
18
+ specify "should not issue an sql query if the schema has been loaded unless :reload is true" do
19
+ INTEGRATION_DB.schema(nil, :reload=>true)
20
+ clear_sqls
21
+ INTEGRATION_DB.schema
22
+ sqls_should_be
23
+ end
24
+
25
+ specify "should give the same result for a single table regardless of whether schema was called for a single table" do
26
+ INTEGRATION_DB.schema(:items, :reload=>true).should == INTEGRATION_DB.schema(nil, :reload=>true)[:items]
27
+ end
28
+
29
+ specify "should return the schema correctly" do
30
+ INTEGRATION_DB.create_table!(:items){integer :number}
31
+ schema = INTEGRATION_DB.schema(:items, :reload=>true)
32
+ schema.should be_a_kind_of(Array)
33
+ schema.length.should == 1
34
+ col = schema.first
35
+ col.should be_a_kind_of(Array)
36
+ col.length.should == 2
37
+ col.first.should == :number
38
+ col_info = col.last
39
+ col_info.should be_a_kind_of(Hash)
40
+ col_info[:type].should == :integer
41
+ clear_sqls
42
+ INTEGRATION_DB.schema(:items)
43
+ sqls_should_be
44
+ end
45
+ end
46
+
47
+ describe "Database schema modifiers" do
48
+ before do
49
+ INTEGRATION_DB.create_table!(:items){integer :number}
50
+ @ds = INTEGRATION_DB[:items]
51
+ @ds.insert([10])
52
+ clear_sqls
53
+ end
54
+ after do
55
+ INTEGRATION_DB.drop_table(:items) if INTEGRATION_DB.table_exists?(:items)
56
+ end
57
+
58
+ specify "should create tables correctly" do
59
+ INTEGRATION_DB.table_exists?(:items).should == true
60
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:number]
61
+ @ds.columns!.should == [:number]
62
+ end
63
+
64
+ specify "should add columns to tables correctly" do
65
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:number]
66
+ @ds.columns!.should == [:number]
67
+ INTEGRATION_DB.alter_table(:items){add_column :name, :text}
68
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:number, :name]
69
+ @ds.columns!.should == [:number, :name]
70
+ unless INTEGRATION_DB.url =~ /sqlite/
71
+ INTEGRATION_DB.alter_table(:items){add_primary_key :id}
72
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:number, :name, :id]
73
+ @ds.columns!.should == [:number, :name, :id]
74
+ unless INTEGRATION_DB.url =~ /mysql/
75
+ INTEGRATION_DB.alter_table(:items){add_foreign_key :item_id, :items}
76
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:number, :name, :id, :item_id]
77
+ @ds.columns!.should == [:number, :name, :id, :item_id]
78
+ end
79
+ end
80
+ end
81
+
82
+ specify "should remove columns from tables correctly" do
83
+ INTEGRATION_DB.create_table!(:items) do
84
+ primary_key :id
85
+ text :name
86
+ integer :number
87
+ foreign_key :item_id, :items
88
+ end
89
+ @ds.insert(:number=>10)
90
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:id, :name, :number, :item_id]
91
+ @ds.columns!.should == [:id, :name, :number, :item_id]
92
+ INTEGRATION_DB.drop_column(:items, :number)
93
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:id, :name, :item_id]
94
+ @ds.columns!.should == [:id, :name, :item_id]
95
+ INTEGRATION_DB.drop_column(:items, :name)
96
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:id, :item_id]
97
+ @ds.columns!.should == [:id, :item_id]
98
+ INTEGRATION_DB.drop_column(:items, :item_id)
99
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:id]
100
+ @ds.columns!.should == [:id]
101
+ end
102
+ end
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ unless Object.const_defined?('Sequel')
3
+ $:.unshift(File.join(File.dirname(__FILE__), "../../lib/"))
4
+ require 'sequel'
5
+ end
6
+ require File.join(File.dirname(__FILE__), '../spec_config.rb')
7
+
8
+ $sqls = []
9
+ def clear_sqls
10
+ $sqls.clear
11
+ end
12
+
13
+ if defined?(INTEGRATION_DB) || defined?(INTEGRATION_URL) || ENV['SEQUEL_INTEGRATION_URL']
14
+ unless defined?(INTEGRATION_DB)
15
+ url = defined?(INTEGRATION_URL) ? INTEGRATION_URL : ENV['SEQUEL_INTEGRATION_URL']
16
+ INTEGRATION_DB = Sequel.connect(url)
17
+ end
18
+ class Spec::Example::ExampleGroup
19
+ def sqls_should_be(*args)
20
+ end
21
+ end
22
+ else
23
+ sql_logger = Object.new
24
+ def sql_logger.info(str)
25
+ $sqls << str
26
+ end
27
+ INTEGRATION_DB = Sequel.sqlite('', :loggers=>[sql_logger], :quote_identifiers=>false)
28
+ class Spec::Example::ExampleGroup
29
+ def sqls_should_be(*sqls)
30
+ sqls.zip($sqls).each do |should_be, is|
31
+ case should_be
32
+ when String
33
+ is.should == should_be
34
+ when Regexp
35
+ is.should =~ should_be
36
+ else
37
+ raise ArgumentError, "need String or RegExp"
38
+ end
39
+ end
40
+ $sqls.length.should == sqls.length
41
+ clear_sqls
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,43 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper.rb')
2
+
3
+ describe "Supported types" do
4
+ def create_items_table_with_column(name, type)
5
+ INTEGRATION_DB.create_table!(:items){column name, type}
6
+ INTEGRATION_DB[:items]
7
+ end
8
+
9
+ specify "should support NULL correctly" do
10
+ ds = create_items_table_with_column(:number, :integer)
11
+ ds.insert(:number => nil)
12
+ ds.all.should == [{:number=>nil}]
13
+ end
14
+
15
+ specify "should support integer type" do
16
+ ds = create_items_table_with_column(:number, :integer)
17
+ ds.insert(:number => 2)
18
+ ds.all.should == [{:number=>2}]
19
+ end
20
+
21
+ specify "should support varchar type" do
22
+ ds = create_items_table_with_column(:name, 'varchar(255)'.lit)
23
+ ds.insert(:name => 'Test User')
24
+ ds.all.should == [{:name=>'Test User'}]
25
+ end
26
+
27
+ specify "should support date type" do
28
+ ds = create_items_table_with_column(:dat, :date)
29
+ d = Date.today
30
+ ds.insert(:dat => d)
31
+ x = ds.first[:dat]
32
+ x = x.iso8601.to_date if Time === x
33
+ x.to_s.should == d.to_s
34
+ end
35
+
36
+ specify "should support time type" do
37
+ ds = create_items_table_with_column(:tim, :time)
38
+ t = Time.now
39
+ ds.insert(:tim => t)
40
+ x = ds.first[:tim]
41
+ [t.strftime('%H:%M:%S'), t.iso8601].should include(x.respond_to?(:strftime) ? x.strftime('%H:%M:%S') : x.to_s)
42
+ end
43
+ end
@@ -2,3 +2,5 @@
2
2
  gems
3
3
  --exclude
4
4
  spec
5
+ --exclude
6
+ 00*
@@ -0,0 +1,363 @@
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(: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).should == :got_connection
60
+ @cpool.send(:make_new).should == :got_connection
61
+ @cpool.send(:make_new).should == nil
62
+ @cpool.created_count.should == 2
63
+ end
64
+ end
65
+
66
+ class DummyConnection
67
+ @@value = 0
68
+ def initialize
69
+ @@value += 1
70
+ end
71
+
72
+ def value
73
+ @@value
74
+ end
75
+ end
76
+
77
+ context "ConnectionPool#hold" do
78
+ setup do
79
+ @pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS) {DummyConnection.new}
80
+ end
81
+
82
+ specify "should pass the result of the connection maker proc to the supplied block" do
83
+ res = nil
84
+ @pool.hold {|c| res = c}
85
+ res.should be_a_kind_of(DummyConnection)
86
+ res.value.should == 1
87
+ @pool.hold {|c| res = c}
88
+ res.should be_a_kind_of(DummyConnection)
89
+ res.value.should == 1 # the connection maker is invoked only once
90
+ end
91
+
92
+ specify "should be re-entrant by the same thread" do
93
+ cc = nil
94
+ @pool.hold {|c| @pool.hold {|c| @pool.hold {|c| cc = c}}}
95
+ cc.should be_a_kind_of(DummyConnection)
96
+ end
97
+
98
+ specify "should catch exceptions and reraise them" do
99
+ proc {@pool.hold {|c| c.foobar}}.should raise_error(NoMethodError)
100
+ end
101
+
102
+ specify "should handle Exception errors (normally not caught by rescue)" do
103
+ err = nil
104
+ begin
105
+ @pool.hold {raise Exception}
106
+ rescue => e
107
+ err = e
108
+ end
109
+ err.should be_a_kind_of(RuntimeError)
110
+ end
111
+ end
112
+
113
+ context "ConnectionPool#connection_proc" do
114
+ setup do
115
+ @pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS)
116
+ end
117
+
118
+ specify "should be nil if no block is supplied to the pool" do
119
+ @pool.connection_proc.should be_nil
120
+ proc {@pool.hold {}}.should raise_error
121
+ end
122
+
123
+ specify "should be mutable" do
124
+ @pool.connection_proc = proc {'herro'}
125
+ res = nil
126
+ proc {@pool.hold {|c| res = c}}.should_not raise_error
127
+ res.should == 'herro'
128
+ end
129
+ end
130
+
131
+ context "A connection pool with a max size of 1" do
132
+ setup do
133
+ @invoked_count = 0
134
+ @pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>1)) {@invoked_count += 1; 'herro'}
135
+ end
136
+
137
+ specify "should let only one thread access the connection at any time" do
138
+ cc,c1, c2 = nil
139
+
140
+ t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup; while c == 'herro';sleep 0.1;end}}
141
+ sleep 0.2
142
+ cc.should == 'herro'
143
+ c1.should == 'herro'
144
+
145
+ t2 = Thread.new {@pool.hold {|c| c2 = c.dup; while c == 'hello';sleep 0.1;end}}
146
+ sleep 0.2
147
+
148
+ # connection held by t1
149
+ t1.should be_alive
150
+ t2.should be_alive
151
+
152
+ cc.should == 'herro'
153
+ c1.should == 'herro'
154
+ c2.should be_nil
155
+
156
+ @pool.available_connections.should be_empty
157
+ @pool.allocated.should == {t1=>cc}
158
+
159
+ cc.gsub!('rr', 'll')
160
+ sleep 0.5
161
+
162
+ # connection held by t2
163
+ t1.should_not be_alive
164
+ t2.should be_alive
165
+
166
+ c2.should == 'hello'
167
+
168
+ @pool.available_connections.should be_empty
169
+ @pool.allocated.should == {t2=>cc}
170
+
171
+ cc.gsub!('ll', 'rr')
172
+ sleep 0.5
173
+
174
+ #connection released
175
+ t2.should_not be_alive
176
+
177
+ cc.should == 'herro'
178
+
179
+ @invoked_count.should == 1
180
+ @pool.size.should == 1
181
+ @pool.available_connections.should == [cc]
182
+ @pool.allocated.should be_empty
183
+ end
184
+
185
+ specify "should let the same thread reenter #hold" do
186
+ c1, c2, c3 = nil
187
+ @pool.hold do |c|
188
+ c1 = c
189
+ @pool.hold do |c|
190
+ c2 = c
191
+ @pool.hold do |c|
192
+ c3 = c
193
+ end
194
+ end
195
+ end
196
+ c1.should == 'herro'
197
+ c2.should == 'herro'
198
+ c3.should == 'herro'
199
+
200
+ @invoked_count.should == 1
201
+ @pool.size.should == 1
202
+ @pool.available_connections.size.should == 1
203
+ @pool.allocated.should be_empty
204
+ end
205
+ end
206
+
207
+ context "A connection pool with a max size of 5" do
208
+ setup do
209
+ @invoked_count = 0
210
+ @pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {@invoked_count += 1}
211
+ end
212
+
213
+ specify "should let five threads simultaneously access separate connections" do
214
+ cc = {}
215
+ threads = []
216
+ stop = nil
217
+
218
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.1;end}}; sleep 0.1}
219
+ sleep 0.2
220
+ threads.each {|t| t.should be_alive}
221
+ cc.size.should == 5
222
+ @invoked_count.should == 5
223
+ @pool.size.should == 5
224
+ @pool.available_connections.should be_empty
225
+ i = 0
226
+ h = {}
227
+ threads.each{|t| h[t] = (i+=1)}
228
+ @pool.allocated.should == h
229
+
230
+ threads[0].raise "your'e dead"
231
+ sleep 0.1
232
+ threads[3].raise "your'e dead too"
233
+
234
+ sleep 0.1
235
+
236
+ @pool.available_connections.should == [1, 4]
237
+ @pool.allocated.should == {threads[1]=>2, threads[2]=>3, threads[4]=>5}
238
+
239
+ stop = true
240
+ sleep 0.2
241
+
242
+ @pool.available_connections.size.should == 5
243
+ @pool.allocated.should be_empty
244
+ end
245
+
246
+ specify "should block threads until a connection becomes available" do
247
+ cc = {}
248
+ threads = []
249
+ stop = nil
250
+
251
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.1;end}}; sleep 0.1}
252
+ sleep 0.2
253
+ threads.each {|t| t.should be_alive}
254
+ @pool.available_connections.should be_empty
255
+
256
+ 3.times {|i| threads << Thread.new {@pool.hold {|c| cc[i + 5] = c}}}
257
+
258
+ sleep 0.2
259
+ threads[5].should be_alive
260
+ threads[6].should be_alive
261
+ threads[7].should be_alive
262
+ cc.size.should == 5
263
+ cc[5].should be_nil
264
+ cc[6].should be_nil
265
+ cc[7].should be_nil
266
+
267
+ stop = true
268
+ sleep 0.3
269
+
270
+ threads.each {|t| t.should_not be_alive}
271
+
272
+ @pool.size.should == 5
273
+ @invoked_count.should == 5
274
+ @pool.available_connections.size.should == 5
275
+ @pool.allocated.should be_empty
276
+ end
277
+ end
278
+
279
+ context "ConnectionPool#disconnect" do
280
+ setup do
281
+ @count = 0
282
+ @pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {{:id => @count += 1}}
283
+ end
284
+
285
+ specify "should invoke the given block for each available connection" do
286
+ threads = []
287
+ stop = nil
288
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
289
+ while @pool.size < 5
290
+ sleep 0.2
291
+ end
292
+ stop = true
293
+ sleep 1
294
+ threads.each {|t| t.join}
295
+
296
+ @pool.size.should == 5
297
+ @pool.available_connections.size.should == 5
298
+ @pool.available_connections.each {|c| c[:id].should_not be_nil}
299
+ conns = []
300
+ @pool.disconnect {|c| conns << c}
301
+ conns.size.should == 5
302
+ end
303
+
304
+ specify "should remove all available connections" do
305
+ threads = []
306
+ stop = nil
307
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
308
+ while @pool.size < 5
309
+ sleep 0.2
310
+ end
311
+ stop = true
312
+ sleep 1
313
+ threads.each {|t| t.join}
314
+
315
+ @pool.size.should == 5
316
+ @pool.disconnect
317
+ @pool.size.should == 0
318
+ end
319
+
320
+ specify "should not touch connections in use" do
321
+ threads = []
322
+ stop = nil
323
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
324
+ while @pool.size < 5
325
+ sleep 0.2
326
+ end
327
+ stop = true
328
+ sleep 1
329
+ threads.each {|t| t.join}
330
+
331
+ @pool.size.should == 5
332
+
333
+ @pool.hold do |conn|
334
+ @pool.available_connections.size.should == 4
335
+ @pool.available_connections.each {|c| c.should_not be(conn)}
336
+ conns = []
337
+ @pool.disconnect {|c| conns << c}
338
+ conns.size.should == 4
339
+ end
340
+ @pool.size.should == 1
341
+ end
342
+ end
343
+
344
+ context "SingleThreadedPool" do
345
+ setup do
346
+ @pool = Sequel::SingleThreadedPool.new(CONNECTION_POOL_DEFAULTS){1234}
347
+ end
348
+
349
+ specify "should provide a #hold method" do
350
+ conn = nil
351
+ @pool.hold {|c| conn = c}
352
+ conn.should == 1234
353
+ end
354
+
355
+ specify "should provide a #disconnect method" do
356
+ @pool.hold {|c|}
357
+ @pool.conn.should == 1234
358
+ conn = nil
359
+ @pool.disconnect {|c| conn = c}
360
+ conn.should == 1234
361
+ @pool.conn.should be_nil
362
+ end
363
+ end