makara 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +28 -0
  7. data/CHANGELOG.md +27 -0
  8. data/Gemfile +18 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +278 -0
  11. data/Rakefile +9 -0
  12. data/gemfiles/ar30.gemfile +30 -0
  13. data/gemfiles/ar31.gemfile +29 -0
  14. data/gemfiles/ar32.gemfile +29 -0
  15. data/gemfiles/ar40.gemfile +15 -0
  16. data/gemfiles/ar41.gemfile +15 -0
  17. data/gemfiles/ar42.gemfile +15 -0
  18. data/lib/active_record/connection_adapters/jdbcmysql_makara_adapter.rb +25 -0
  19. data/lib/active_record/connection_adapters/jdbcpostgresql_makara_adapter.rb +25 -0
  20. data/lib/active_record/connection_adapters/makara_abstract_adapter.rb +209 -0
  21. data/lib/active_record/connection_adapters/makara_jdbcmysql_adapter.rb +25 -0
  22. data/lib/active_record/connection_adapters/makara_jdbcpostgresql_adapter.rb +25 -0
  23. data/lib/active_record/connection_adapters/makara_mysql2_adapter.rb +44 -0
  24. data/lib/active_record/connection_adapters/makara_postgresql_adapter.rb +44 -0
  25. data/lib/active_record/connection_adapters/mysql2_makara_adapter.rb +44 -0
  26. data/lib/active_record/connection_adapters/postgresql_makara_adapter.rb +44 -0
  27. data/lib/makara.rb +25 -0
  28. data/lib/makara/cache.rb +53 -0
  29. data/lib/makara/cache/memory_store.rb +28 -0
  30. data/lib/makara/cache/noop_store.rb +15 -0
  31. data/lib/makara/config_parser.rb +200 -0
  32. data/lib/makara/connection_wrapper.rb +170 -0
  33. data/lib/makara/context.rb +46 -0
  34. data/lib/makara/error_handler.rb +39 -0
  35. data/lib/makara/errors/all_connections_blacklisted.rb +13 -0
  36. data/lib/makara/errors/blacklist_connection.rb +14 -0
  37. data/lib/makara/errors/no_connections_available.rb +14 -0
  38. data/lib/makara/logging/logger.rb +23 -0
  39. data/lib/makara/logging/subscriber.rb +38 -0
  40. data/lib/makara/middleware.rb +109 -0
  41. data/lib/makara/pool.rb +188 -0
  42. data/lib/makara/proxy.rb +277 -0
  43. data/lib/makara/railtie.rb +14 -0
  44. data/lib/makara/version.rb +15 -0
  45. data/makara.gemspec +19 -0
  46. data/spec/active_record/connection_adapters/makara_abstract_adapter_error_handling_spec.rb +92 -0
  47. data/spec/active_record/connection_adapters/makara_abstract_adapter_spec.rb +114 -0
  48. data/spec/active_record/connection_adapters/makara_mysql2_adapter_spec.rb +183 -0
  49. data/spec/active_record/connection_adapters/makara_postgresql_adapter_spec.rb +121 -0
  50. data/spec/cache_spec.rb +59 -0
  51. data/spec/config_parser_spec.rb +102 -0
  52. data/spec/connection_wrapper_spec.rb +33 -0
  53. data/spec/context_spec.rb +107 -0
  54. data/spec/middleware_spec.rb +84 -0
  55. data/spec/pool_spec.rb +158 -0
  56. data/spec/proxy_spec.rb +182 -0
  57. data/spec/spec_helper.rb +46 -0
  58. data/spec/support/configurator.rb +13 -0
  59. data/spec/support/deep_dup.rb +12 -0
  60. data/spec/support/mock_objects.rb +67 -0
  61. data/spec/support/mysql2_database.yml +17 -0
  62. data/spec/support/mysql2_database_with_custom_errors.yml +17 -0
  63. data/spec/support/pool_extensions.rb +14 -0
  64. data/spec/support/postgresql_database.yml +13 -0
  65. data/spec/support/proxy_extensions.rb +33 -0
  66. data/spec/support/schema.rb +7 -0
  67. metadata +144 -0
@@ -0,0 +1,182 @@
1
+ require 'spec_helper'
2
+
3
+ describe Makara::Proxy do
4
+
5
+ let(:klass){ FakeProxy }
6
+
7
+
8
+ it 'sets up a master and slave pool no matter the number of connections' do
9
+ proxy = klass.new(config(0, 0))
10
+ expect(proxy.master_pool).to be_a(Makara::Pool)
11
+ expect(proxy.slave_pool).to be_a(Makara::Pool)
12
+
13
+ proxy = klass.new(config(2, 0))
14
+ expect(proxy.master_pool).to be_a(Makara::Pool)
15
+ expect(proxy.slave_pool).to be_a(Makara::Pool)
16
+
17
+ proxy = klass.new(config(0, 2))
18
+ expect(proxy.master_pool).to be_a(Makara::Pool)
19
+ expect(proxy.slave_pool).to be_a(Makara::Pool)
20
+
21
+ proxy = klass.new(config(2, 2))
22
+ expect(proxy.master_pool).to be_a(Makara::Pool)
23
+ expect(proxy.slave_pool).to be_a(Makara::Pool)
24
+ end
25
+
26
+
27
+ it 'instantiates N connections within each pool' do
28
+ proxy = klass.new(config(1, 2))
29
+
30
+ expect(proxy.master_pool.connection_count).to eq(1)
31
+ expect(proxy.slave_pool.connection_count).to eq(2)
32
+ end
33
+
34
+ it 'should delegate any unknown method to a connection in the master pool' do
35
+ proxy = klass.new(config(1, 2))
36
+
37
+ con = proxy.master_pool.connections.first
38
+ allow(con).to receive(:irespondtothis){ 'hello!' }
39
+
40
+ expect(proxy).to respond_to(:irespondtothis)
41
+ expect(proxy.irespondtothis).to eq('hello!')
42
+ end
43
+
44
+ it 'should use master if manually forced' do
45
+ proxy = klass.new(config(1, 2))
46
+
47
+ expect(proxy.master_for?('select * from users')).to eq(false)
48
+
49
+ proxy.stick_to_master!
50
+
51
+ expect(proxy.master_for?('select * from users')).to eq(true)
52
+ end
53
+
54
+
55
+ context '#appropriate_pool' do
56
+
57
+ let(:proxy){ klass.new(config(1,1)) }
58
+
59
+ it 'should be sticky by default' do
60
+ expect(proxy.sticky).to eq(true)
61
+ end
62
+
63
+ it 'should provide the slave pool for a read' do
64
+ expect(proxy.master_for?('select * from users')).to eq(false)
65
+ end
66
+
67
+ it 'should provide the master pool for a write' do
68
+ expect(proxy.master_for?('insert into users values (a,b,c)')).to eq(true)
69
+ end
70
+
71
+ # master is used, it should continue being used for the duration of the context
72
+ it 'should stick to master once used for a sticky operation' do
73
+ expect(proxy.master_for?('insert into users values (a,b,c)')).to eq(true)
74
+ expect(proxy.master_for?('select * from users')).to eq(true)
75
+ end
76
+
77
+ it 'should not stick to master if stickiness is disabled' do
78
+ proxy.sticky = false
79
+ expect(proxy.master_for?('insert into users values (a,b,c)')).to eq(true)
80
+ expect(proxy.master_for?('select * from users')).to eq(false)
81
+ end
82
+
83
+ it 'should not stick to master if we are in a without_sticking block' do
84
+ proxy.without_sticking do
85
+ expect(proxy.master_for?('insert into users values (a,b,c)')).to eq(true)
86
+ expect(proxy.master_for?('select * from users')).to eq(false)
87
+ end
88
+
89
+ expect(proxy.master_for?('insert into users values (a,b,c)')).to eq(true)
90
+ expect(proxy.master_for?('select * from users')).to eq(true)
91
+ end
92
+
93
+ # if the context changes we should still use master until the previous context is no longer relevant
94
+ it 'should release master if the context changes and enough time passes' do
95
+ expect(proxy.master_for?('insert into users values (a,b,c)')).to eq(true)
96
+ expect(proxy.master_for?('select * from users')).to eq(true)
97
+
98
+ change_context
99
+
100
+ Timecop.travel Time.now + 10 do
101
+ expect(proxy.master_for?('select * from users')).to eq(false)
102
+ end
103
+ end
104
+
105
+ it 'should not release master if the previous context is still relevant' do
106
+ expect(proxy.master_for?('insert into users values (a,b,c)')).to eq(true)
107
+ expect(proxy.master_for?('select * from users')).to eq(true)
108
+
109
+ roll_context
110
+
111
+ proxy.master_for?('select * from users')
112
+ expect(proxy.master_for?('select * from users')).to eq(true)
113
+
114
+ Timecop.travel Time.now + 10 do
115
+ # cache is expired but context has not changed
116
+ expect(proxy.master_for?('select * from users')).to eq(true)
117
+
118
+ roll_context
119
+
120
+ expect(proxy.master_for?('select * from users')).to eq(false)
121
+ end
122
+ end
123
+
124
+ it 'should release master if context changes enough' do
125
+ expect(proxy.master_for?('insert into users values (a,b,c)')).to eq(true)
126
+ roll_context
127
+ roll_context
128
+ expect(proxy.master_for?('select * from users')).to eq(false)
129
+ end
130
+
131
+ it 'should use master if all slaves are blacklisted' do
132
+ allow(proxy.slave_pool).to receive(:completely_blacklisted?){ true }
133
+ expect(proxy.master_for?('select * from users')).to eq(true)
134
+ end
135
+
136
+ it 'should use master if all slaves become blacklisted as part of the invocation' do
137
+ allow(proxy.slave_pool).to receive(:next).and_return(nil)
138
+
139
+ test = double
140
+ expect(test).to receive(:blacklisting).once
141
+ expect(test).to receive(:using_master).once
142
+
143
+ proxy.send(:appropriate_pool, :execute, ['select * from users']) do |pool|
144
+ if pool == proxy.slave_pool
145
+ test.blacklisting
146
+ pool.instance_variable_get('@blacklist_errors') << StandardError.new('some connection issue')
147
+ pool.connections.each(&:_makara_blacklist!)
148
+ pool.provide
149
+ else
150
+ test.using_master
151
+ end
152
+ end
153
+ end
154
+
155
+ it 'should raise the error and whitelist all connections if everything is blacklisted (start over)' do
156
+ proxy.ping
157
+
158
+ # weird setup to allow for the correct
159
+ proxy.slave_pool.connections.each(&:_makara_blacklist!)
160
+ proxy.slave_pool.instance_variable_get('@blacklist_errors') << StandardError.new('some slave connection issue')
161
+ proxy.master_pool.connections.each(&:_makara_blacklist!)
162
+ proxy.master_pool.instance_variable_get('@blacklist_errors') << StandardError.new('some master connection issue')
163
+
164
+ allow(proxy).to receive(:_appropriate_pool).and_return(proxy.slave_pool, proxy.master_pool)
165
+
166
+ begin
167
+ proxy.send(:appropriate_pool, :execute, ['select * from users']) do |pool|
168
+ pool.provide{|c| c }
169
+ end
170
+ rescue Makara::Errors::AllConnectionsBlacklisted => e
171
+ expect(e.message).to eq('[Makara/master] All connections are blacklisted -> some master connection issue -> [Makara/slave] All connections are blacklisted -> some slave connection issue')
172
+ end
173
+
174
+ proxy.slave_pool.connections.each{|con| expect(con._makara_blacklisted?).to eq(false) }
175
+ proxy.master_pool.connections.each{|con| expect(con._makara_blacklisted?).to eq(false) }
176
+ end
177
+
178
+ end
179
+
180
+
181
+
182
+ end
@@ -0,0 +1,46 @@
1
+ require 'active_record'
2
+ require 'makara'
3
+ require 'timecop'
4
+ require 'yaml'
5
+
6
+ begin
7
+ require 'byebug'
8
+ rescue LoadError
9
+ end
10
+
11
+ begin
12
+ require 'ruby-debug'
13
+ rescue LoadError
14
+ end
15
+
16
+ RSpec.configure do |config|
17
+ config.run_all_when_everything_filtered = true
18
+ config.filter_run :focus
19
+
20
+ config.order = 'random'
21
+
22
+ require "#{File.dirname(__FILE__)}/support/proxy_extensions"
23
+ require "#{File.dirname(__FILE__)}/support/pool_extensions"
24
+ require "#{File.dirname(__FILE__)}/support/configurator"
25
+ require "#{File.dirname(__FILE__)}/support/mock_objects"
26
+ require "#{File.dirname(__FILE__)}/support/deep_dup"
27
+
28
+ config.include Configurator
29
+
30
+ config.before :each do
31
+ Makara::Cache.store = :memory
32
+ change_context
33
+ allow_any_instance_of(Makara::Pool).to receive(:should_shuffle?){ false }
34
+ end
35
+
36
+ def change_context
37
+ Makara::Context.set_previous nil
38
+ Makara::Context.set_current nil
39
+ end
40
+
41
+ def roll_context
42
+ Makara::Context.set_previous Makara::Context.get_current
43
+ Makara::Context.set_current Makara::Context.generate
44
+ end
45
+
46
+ end
@@ -0,0 +1,13 @@
1
+ module Configurator
2
+ def config(masters = 1, slaves = 2)
3
+ connections = []
4
+ masters.times{ connections << {:role => 'master'} }
5
+ slaves.times{ connections << {:role => 'slave'} }
6
+ {
7
+ :makara => {
8
+ :blacklist_duration => 30,
9
+ :connections => connections
10
+ }
11
+ }
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ unless Hash.respond_to?(:deep_dup)
2
+ class Hash
3
+ def deep_dup
4
+ duplicate = self.dup
5
+ duplicate.each_pair do |k,v|
6
+ tv = duplicate[k]
7
+ duplicate[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_dup : v
8
+ end
9
+ duplicate
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,67 @@
1
+ require 'active_record/connection_adapters/makara_abstract_adapter'
2
+
3
+ class FakeConnection < Struct.new(:config)
4
+
5
+ attr_accessor :something
6
+
7
+ def ping
8
+ 'ping!'
9
+ end
10
+
11
+ def irespondtothis
12
+ 'hey!'
13
+ end
14
+
15
+ def query(content)
16
+ []
17
+ end
18
+
19
+ def active?
20
+ true
21
+ end
22
+
23
+ def disconnect!
24
+ true
25
+ end
26
+ end
27
+
28
+ class FakeDatabaseAdapter < Struct.new(:config)
29
+
30
+ def execute(sql, name = nil)
31
+ []
32
+ end
33
+
34
+ def exec_query(sql, name = 'SQL', binds = [])
35
+ []
36
+ end
37
+
38
+ def select_rows(sql, name = nil)
39
+ []
40
+ end
41
+
42
+ def active?
43
+ true
44
+ end
45
+
46
+ end
47
+
48
+ class FakeProxy < Makara::Proxy
49
+
50
+ send_to_all :ping
51
+ hijack_method :execute
52
+
53
+ def connection_for(config)
54
+ FakeConnection.new(config)
55
+ end
56
+
57
+ def needs_master?(method_name, args)
58
+ return false if args.first =~ /^select/
59
+ true
60
+ end
61
+ end
62
+
63
+ class FakeAdapter < ::ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter
64
+ def connection_for(config)
65
+ FakeDatabaseAdapter.new(config)
66
+ end
67
+ end
@@ -0,0 +1,17 @@
1
+ test:
2
+ adapter: 'mysql2_makara'
3
+ database: 'makara_test'
4
+ username: 'root'
5
+ password: ''
6
+
7
+ connect_timeout: 1
8
+ read_timeout: 1
9
+ write_timeout: 2
10
+
11
+ makara:
12
+ blacklist_duration: 2
13
+ master_ttl: 5
14
+ connections:
15
+ - role: master
16
+ - role: slave
17
+ - role: slave
@@ -0,0 +1,17 @@
1
+ test:
2
+ adapter: 'mysql2_makara'
3
+ database: 'makara_test'
4
+ username: 'root'
5
+ password: ''
6
+
7
+ makara:
8
+ blacklist_duration: 2
9
+ master_ttl: 5
10
+ connections:
11
+ - role: master
12
+ - role: slave
13
+ - role: slave
14
+ connection_error_matchers:
15
+ - !ruby/regexp '/^ActiveRecord::StatementInvalid: Mysql2::Error: Unknown command1:/'
16
+ - "/^ActiveRecord::StatementInvalid: Mysql2::Error: Unknown command2:/i"
17
+ - "ActiveRecord::StatementInvalid: Mysql2::Error: Unknown command3:"
@@ -0,0 +1,14 @@
1
+ module PoolExtensions
2
+
3
+ def connections
4
+ @connections
5
+ end
6
+
7
+ def connection_count
8
+ @connections.length
9
+ end
10
+
11
+ end
12
+
13
+
14
+ Makara::Pool.send(:include, PoolExtensions)
@@ -0,0 +1,13 @@
1
+ test:
2
+ adapter: 'postgresql_makara'
3
+ database: 'makara_test'
4
+ username: 'root'
5
+ password: ''
6
+
7
+ makara:
8
+ blacklist_duration: 2
9
+ master_ttl: 5
10
+ connections:
11
+ - role: master
12
+ - role: slave
13
+ - role: slave
@@ -0,0 +1,33 @@
1
+ module ProxyExtensions
2
+
3
+ attr_reader :master_pool, :slave_pool, :master_context, :id
4
+
5
+ def master_for?(sql)
6
+ pool_for(sql) == master_pool
7
+ end
8
+
9
+ def would_stick?(sql)
10
+ should_stick?(:execute, [sql])
11
+ end
12
+
13
+ def connection_for(sql)
14
+ pool_for(sql) do |pool|
15
+ pool.provide do |connection|
16
+ connection
17
+ end
18
+ end
19
+ end
20
+
21
+ def pool_for(sql)
22
+ appropriate_pool(:execute, [sql]) do |pool|
23
+ pool
24
+ end
25
+ end
26
+
27
+ def sticky=(s)
28
+ @sticky = s
29
+ end
30
+
31
+ end
32
+
33
+ Makara::Proxy.send(:include, ProxyExtensions)
@@ -0,0 +1,7 @@
1
+ ActiveRecord::Schema.define(:version => 20130628161227) do
2
+
3
+ create_table "users", :force => true do |t|
4
+ t.string "name"
5
+ end
6
+
7
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: makara
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.5
5
+ platform: ruby
6
+ authors:
7
+ - Mike Nelson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.0
27
+ description: Read-write split your DB yo
28
+ email:
29
+ - mike@mikeonrails.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gitignore"
35
+ - ".rspec"
36
+ - ".ruby-gemset"
37
+ - ".ruby-version"
38
+ - ".travis.yml"
39
+ - CHANGELOG.md
40
+ - Gemfile
41
+ - LICENSE.txt
42
+ - README.md
43
+ - Rakefile
44
+ - gemfiles/ar30.gemfile
45
+ - gemfiles/ar31.gemfile
46
+ - gemfiles/ar32.gemfile
47
+ - gemfiles/ar40.gemfile
48
+ - gemfiles/ar41.gemfile
49
+ - gemfiles/ar42.gemfile
50
+ - lib/active_record/connection_adapters/jdbcmysql_makara_adapter.rb
51
+ - lib/active_record/connection_adapters/jdbcpostgresql_makara_adapter.rb
52
+ - lib/active_record/connection_adapters/makara_abstract_adapter.rb
53
+ - lib/active_record/connection_adapters/makara_jdbcmysql_adapter.rb
54
+ - lib/active_record/connection_adapters/makara_jdbcpostgresql_adapter.rb
55
+ - lib/active_record/connection_adapters/makara_mysql2_adapter.rb
56
+ - lib/active_record/connection_adapters/makara_postgresql_adapter.rb
57
+ - lib/active_record/connection_adapters/mysql2_makara_adapter.rb
58
+ - lib/active_record/connection_adapters/postgresql_makara_adapter.rb
59
+ - lib/makara.rb
60
+ - lib/makara/cache.rb
61
+ - lib/makara/cache/memory_store.rb
62
+ - lib/makara/cache/noop_store.rb
63
+ - lib/makara/config_parser.rb
64
+ - lib/makara/connection_wrapper.rb
65
+ - lib/makara/context.rb
66
+ - lib/makara/error_handler.rb
67
+ - lib/makara/errors/all_connections_blacklisted.rb
68
+ - lib/makara/errors/blacklist_connection.rb
69
+ - lib/makara/errors/no_connections_available.rb
70
+ - lib/makara/logging/logger.rb
71
+ - lib/makara/logging/subscriber.rb
72
+ - lib/makara/middleware.rb
73
+ - lib/makara/pool.rb
74
+ - lib/makara/proxy.rb
75
+ - lib/makara/railtie.rb
76
+ - lib/makara/version.rb
77
+ - makara.gemspec
78
+ - spec/active_record/connection_adapters/makara_abstract_adapter_error_handling_spec.rb
79
+ - spec/active_record/connection_adapters/makara_abstract_adapter_spec.rb
80
+ - spec/active_record/connection_adapters/makara_mysql2_adapter_spec.rb
81
+ - spec/active_record/connection_adapters/makara_postgresql_adapter_spec.rb
82
+ - spec/cache_spec.rb
83
+ - spec/config_parser_spec.rb
84
+ - spec/connection_wrapper_spec.rb
85
+ - spec/context_spec.rb
86
+ - spec/middleware_spec.rb
87
+ - spec/pool_spec.rb
88
+ - spec/proxy_spec.rb
89
+ - spec/spec_helper.rb
90
+ - spec/support/configurator.rb
91
+ - spec/support/deep_dup.rb
92
+ - spec/support/mock_objects.rb
93
+ - spec/support/mysql2_database.yml
94
+ - spec/support/mysql2_database_with_custom_errors.yml
95
+ - spec/support/pool_extensions.rb
96
+ - spec/support/postgresql_database.yml
97
+ - spec/support/proxy_extensions.rb
98
+ - spec/support/schema.rb
99
+ homepage: ''
100
+ licenses: []
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 2.6.1
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: Read-write split your DB yo
122
+ test_files:
123
+ - spec/active_record/connection_adapters/makara_abstract_adapter_error_handling_spec.rb
124
+ - spec/active_record/connection_adapters/makara_abstract_adapter_spec.rb
125
+ - spec/active_record/connection_adapters/makara_mysql2_adapter_spec.rb
126
+ - spec/active_record/connection_adapters/makara_postgresql_adapter_spec.rb
127
+ - spec/cache_spec.rb
128
+ - spec/config_parser_spec.rb
129
+ - spec/connection_wrapper_spec.rb
130
+ - spec/context_spec.rb
131
+ - spec/middleware_spec.rb
132
+ - spec/pool_spec.rb
133
+ - spec/proxy_spec.rb
134
+ - spec/spec_helper.rb
135
+ - spec/support/configurator.rb
136
+ - spec/support/deep_dup.rb
137
+ - spec/support/mock_objects.rb
138
+ - spec/support/mysql2_database.yml
139
+ - spec/support/mysql2_database_with_custom_errors.yml
140
+ - spec/support/pool_extensions.rb
141
+ - spec/support/postgresql_database.yml
142
+ - spec/support/proxy_extensions.rb
143
+ - spec/support/schema.rb
144
+ has_rdoc: