makara 0.4.1 → 0.5.1

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 (88) hide show
  1. checksums.yaml +5 -5
  2. data/.github/dependabot.yml +11 -0
  3. data/.github/workflows/CI.yml +88 -0
  4. data/.github/workflows/gem-publish-public.yml +36 -0
  5. data/.rspec +1 -1
  6. data/.rubocop.yml +15 -0
  7. data/.rubocop_todo.yml +670 -0
  8. data/CHANGELOG.md +69 -48
  9. data/Gemfile +1 -16
  10. data/README.md +8 -9
  11. data/Rakefile +1 -1
  12. data/gemfiles/activerecord_5.2.gemfile +8 -0
  13. data/gemfiles/activerecord_6.0.gemfile +8 -0
  14. data/gemfiles/activerecord_6.1.gemfile +8 -0
  15. data/gemfiles/activerecord_head.gemfile +6 -0
  16. data/lib/active_record/connection_adapters/jdbcmysql_makara_adapter.rb +4 -18
  17. data/lib/active_record/connection_adapters/jdbcpostgresql_makara_adapter.rb +4 -18
  18. data/lib/active_record/connection_adapters/makara_abstract_adapter.rb +107 -30
  19. data/lib/active_record/connection_adapters/makara_jdbcmysql_adapter.rb +4 -18
  20. data/lib/active_record/connection_adapters/makara_jdbcpostgresql_adapter.rb +4 -18
  21. data/lib/active_record/connection_adapters/makara_mysql2_adapter.rb +4 -20
  22. data/lib/active_record/connection_adapters/makara_postgis_adapter.rb +4 -19
  23. data/lib/active_record/connection_adapters/makara_postgresql_adapter.rb +4 -20
  24. data/lib/active_record/connection_adapters/mysql2_makara_adapter.rb +4 -20
  25. data/lib/active_record/connection_adapters/postgresql_makara_adapter.rb +4 -20
  26. data/lib/makara/cache.rb +0 -2
  27. data/lib/makara/config_parser.rb +7 -15
  28. data/lib/makara/connection_wrapper.rb +43 -22
  29. data/lib/makara/context.rb +1 -0
  30. data/lib/makara/cookie.rb +1 -0
  31. data/lib/makara/error_handler.rb +0 -9
  32. data/lib/makara/errors/all_connections_blacklisted.rb +0 -2
  33. data/lib/makara/errors/blacklist_connection.rb +0 -2
  34. data/lib/makara/errors/blacklisted_while_in_transaction.rb +12 -0
  35. data/lib/makara/errors/invalid_shard.rb +14 -0
  36. data/lib/makara/errors/makara_error.rb +0 -1
  37. data/lib/makara/errors/no_connections_available.rb +0 -2
  38. data/lib/makara/logging/logger.rb +0 -4
  39. data/lib/makara/logging/subscriber.rb +0 -2
  40. data/lib/makara/middleware.rb +1 -2
  41. data/lib/makara/pool.rb +49 -31
  42. data/lib/makara/proxy.rb +56 -30
  43. data/lib/makara/railtie.rb +0 -2
  44. data/lib/makara/strategies/abstract.rb +1 -0
  45. data/lib/makara/strategies/priority_failover.rb +2 -0
  46. data/lib/makara/strategies/round_robin.rb +1 -3
  47. data/lib/makara/strategies/shard_aware.rb +45 -0
  48. data/lib/makara/version.rb +1 -3
  49. data/lib/makara.rb +7 -6
  50. data/makara.gemspec +26 -3
  51. data/spec/active_record/connection_adapters/makara_abstract_adapter_error_handling_spec.rb +1 -6
  52. data/spec/active_record/connection_adapters/makara_abstract_adapter_spec.rb +0 -9
  53. data/spec/active_record/connection_adapters/makara_mysql2_adapter_spec.rb +9 -22
  54. data/spec/active_record/connection_adapters/makara_postgis_adapter_spec.rb +2 -10
  55. data/spec/active_record/connection_adapters/makara_postgresql_adapter_spec.rb +62 -18
  56. data/spec/cache_spec.rb +0 -1
  57. data/spec/config_parser_spec.rb +54 -56
  58. data/spec/connection_wrapper_spec.rb +1 -2
  59. data/spec/cookie_spec.rb +4 -4
  60. data/spec/middleware_spec.rb +2 -2
  61. data/spec/pool_spec.rb +25 -14
  62. data/spec/proxy_spec.rb +0 -4
  63. data/spec/spec_helper.rb +6 -1
  64. data/spec/strategies/priority_failover_spec.rb +3 -4
  65. data/spec/strategies/round_robin_spec.rb +4 -8
  66. data/spec/strategies/shard_aware_spec.rb +218 -0
  67. data/spec/support/deep_dup.rb +1 -1
  68. data/spec/support/helpers.rb +5 -5
  69. data/spec/support/mock_objects.rb +5 -4
  70. data/spec/support/mysql2_database.yml +2 -2
  71. data/spec/support/mysql2_database_with_custom_errors.yml +2 -2
  72. data/spec/support/pool_extensions.rb +0 -3
  73. data/spec/support/postgis_schema.rb +1 -1
  74. data/spec/support/postgresql_database.yml +0 -2
  75. data/spec/support/proxy_extensions.rb +1 -3
  76. data/spec/support/schema.rb +1 -1
  77. data/spec/support/user.rb +1 -2
  78. metadata +165 -20
  79. data/.travis.yml +0 -105
  80. data/gemfiles/ar-head.gemfile +0 -24
  81. data/gemfiles/ar30.gemfile +0 -36
  82. data/gemfiles/ar31.gemfile +0 -36
  83. data/gemfiles/ar32.gemfile +0 -36
  84. data/gemfiles/ar40.gemfile +0 -24
  85. data/gemfiles/ar41.gemfile +0 -24
  86. data/gemfiles/ar42.gemfile +0 -24
  87. data/gemfiles/ar50.gemfile +0 -24
  88. data/gemfiles/ar51.gemfile +0 -24
@@ -2,12 +2,10 @@ require 'spec_helper'
2
2
  require 'active_record/connection_adapters/mysql2_adapter'
3
3
 
4
4
  describe 'MakaraMysql2Adapter' do
5
-
6
- let(:db_username){ ENV['TRAVIS'] ? 'travis' : 'root' }
7
-
8
5
  let(:config){
9
- base = YAML.load_file(File.expand_path('spec/support/mysql2_database.yml'))['test']
10
- base
6
+ file = File.expand_path('spec/support/mysql2_database.yml')
7
+ hash = YAML.load(ERB.new(File.read(file)).result)
8
+ hash['test']
11
9
  }
12
10
 
13
11
  let(:connection) { ActiveRecord::Base.connection }
@@ -18,7 +16,6 @@ describe 'MakaraMysql2Adapter' do
18
16
  end
19
17
 
20
18
  context "unconnected" do
21
-
22
19
  it 'should allow a connection to be established' do
23
20
  establish_connection(config)
24
21
  expect(ActiveRecord::Base.connection).to be_instance_of(ActiveRecord::ConnectionAdapters::MakaraMysql2Adapter)
@@ -56,7 +53,6 @@ describe 'MakaraMysql2Adapter' do
56
53
  expect{
57
54
  connection.execute('SET @t1 = 1')
58
55
  }.to raise_error(Makara::Errors::NoConnectionsAvailable)
59
-
60
56
  end
61
57
 
62
58
  context "unconnect afterwards" do
@@ -84,8 +80,7 @@ describe 'MakaraMysql2Adapter' do
84
80
  load(File.dirname(__FILE__) + '/../../support/schema.rb')
85
81
  change_context
86
82
 
87
- allow(ActiveRecord::Base).to receive(:mysql2_connection) do |config|
88
- config[:username] = db_username
83
+ allow(ActiveRecord::Base).to receive(:mysql2_connection) do
89
84
  original_method.call(config)
90
85
  end
91
86
 
@@ -102,18 +97,15 @@ describe 'MakaraMysql2Adapter' do
102
97
  ActiveRecord::Base.remove_connection
103
98
  end
104
99
  end
105
-
106
100
  end
107
101
 
108
102
  context 'with the connection established and schema loaded' do
109
-
110
103
  before do
111
104
  establish_connection(config)
112
105
  load(File.dirname(__FILE__) + '/../../support/schema.rb')
113
106
  change_context
114
107
  end
115
108
 
116
-
117
109
  it 'should have one master and two slaves' do
118
110
  expect(connection.master_pool.connection_count).to eq(1)
119
111
  expect(connection.slave_pool.connection_count).to eq(2)
@@ -159,17 +151,14 @@ describe 'MakaraMysql2Adapter' do
159
151
  end
160
152
 
161
153
  it 'should send exists? to slave' do
162
- next if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0 # query doesn't work?
163
-
164
154
  allow_any_instance_of(Makara::Strategies::RoundRobin).to receive(:single_one?){ true }
165
155
  Test::User.exists? # flush other (schema) things that need to happen
166
-
156
+
167
157
  con = connection.slave_pool.connections.first
168
- if (ActiveRecord::VERSION::MAJOR == 5 && ActiveRecord::VERSION::MINOR <= 0)
169
- expect(con).to receive(:execute).with(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/, any_args).once.and_call_original
170
- else
171
- expect(con).to receive(:exec_query).with(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/, any_args).once.and_call_original
172
- end
158
+ expect(con).to receive(:exec_query) do |query|
159
+ expect(query).to match(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/)
160
+ end.once.and_call_original
161
+
173
162
  Test::User.exists?
174
163
  end
175
164
 
@@ -198,7 +187,6 @@ describe 'MakaraMysql2Adapter' do
198
187
  }.to raise_error(Makara::Errors::AllConnectionsBlacklisted)
199
188
  end
200
189
  end
201
-
202
190
  end
203
191
 
204
192
  describe 'transaction support' do
@@ -256,5 +244,4 @@ describe 'MakaraMysql2Adapter' do
256
244
  it_behaves_like 'a transaction supporter'
257
245
  end
258
246
  end
259
-
260
247
  end
@@ -1,16 +1,12 @@
1
1
  # RGeo doesn't play well with JRuby and to avoid complicated test setup
2
2
  # we're only testing ActiveRecord version ~> 4.2
3
- # also rgeo only works on 2.1+
4
3
 
5
- rmajor, rminor, rpatch = RUBY_VERSION.split(/[^\d]/)[0..2].map(&:to_i)
6
4
  require 'active_record'
7
5
 
8
6
  # TODO: test this in AR 5+ ?
9
-
10
7
  if RUBY_ENGINE == 'ruby' &&
11
8
  ActiveRecord::VERSION::MAJOR == 4 &&
12
- ActiveRecord::VERSION::MINOR >= 2 &&
13
- (rmajor > 2 || (rmajor == 2 && rminor >= 1))
9
+ ActiveRecord::VERSION::MINOR >= 2
14
10
 
15
11
  require 'spec_helper'
16
12
  require 'rgeo'
@@ -18,12 +14,8 @@ if RUBY_ENGINE == 'ruby' &&
18
14
  require 'active_record/connection_adapters/postgis_adapter'
19
15
 
20
16
  describe 'MakaraPostgisAdapter' do
21
- let(:db_username){ ENV['TRAVIS'] ? 'postgres' : `whoami`.chomp }
22
-
23
17
  let(:config) do
24
- base = YAML.load_file(File.expand_path('spec/support/postgis_database.yml'))['test']
25
- base['username'] = db_username
26
- base
18
+ YAML.load_file(File.expand_path('spec/support/postgis_database.yml'))['test']
27
19
  end
28
20
 
29
21
  let(:connection) { ActiveRecord::Base.connection }
@@ -1,14 +1,10 @@
1
1
  require 'spec_helper'
2
2
  require 'active_record/connection_adapters/postgresql_adapter'
3
+ require 'active_record/errors'
3
4
 
4
5
  describe 'MakaraPostgreSQLAdapter' do
5
-
6
- let(:db_username){ ENV['TRAVIS'] ? 'postgres' : `whoami`.chomp }
7
-
8
6
  let(:config) do
9
- base = YAML.load_file(File.expand_path('spec/support/postgresql_database.yml'))['test']
10
- base['username'] = db_username
11
- base
7
+ YAML.load_file(File.expand_path('spec/support/postgresql_database.yml'))['test']
12
8
  end
13
9
 
14
10
  let(:connection) { ActiveRecord::Base.connection }
@@ -18,21 +14,18 @@ describe 'MakaraPostgreSQLAdapter' do
18
14
  change_context
19
15
  end
20
16
 
21
-
22
17
  it 'should allow a connection to be established' do
23
18
  establish_connection(config)
24
19
  expect(ActiveRecord::Base.connection).to be_instance_of(ActiveRecord::ConnectionAdapters::MakaraPostgreSQLAdapter)
25
20
  end
26
21
 
27
22
  context 'with the connection established and schema loaded' do
28
-
29
23
  before do
30
24
  establish_connection(config)
31
25
  load(File.dirname(__FILE__) + '/../../support/schema.rb')
32
26
  change_context
33
27
  end
34
28
 
35
-
36
29
  it 'should have one master and two slaves' do
37
30
  expect(connection.master_pool.connection_count).to eq(1)
38
31
  expect(connection.slave_pool.connection_count).to eq(2)
@@ -73,18 +66,15 @@ describe 'MakaraPostgreSQLAdapter' do
73
66
  end
74
67
 
75
68
  it 'should send exists? to slave' do
76
- next if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0 # query doesn't work?
77
-
78
69
  allow_any_instance_of(Makara::Strategies::RoundRobin).to receive(:single_one?){ true }
79
70
  Test::User.exists? # flush other (schema) things that need to happen
80
-
71
+
81
72
  con = connection.slave_pool.connections.first
82
- if (ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR >= 2) ||
83
- (ActiveRecord::VERSION::MAJOR == 5 && ActiveRecord::VERSION::MINOR <= 0)
84
- expect(con).to receive(:exec_no_cache).with(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/, any_args).once.and_call_original
85
- else
86
- expect(con).to receive(:exec_query).with(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/, any_args).once.and_call_original
87
- end
73
+
74
+ expect(con).to receive(:exec_query) do |query|
75
+ expect(query).to match(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/)
76
+ end.once.and_call_original
77
+
88
78
  Test::User.exists?
89
79
  end
90
80
 
@@ -191,4 +181,58 @@ describe 'MakaraPostgreSQLAdapter' do
191
181
  it_behaves_like 'a transaction supporter'
192
182
  end
193
183
  end
184
+
185
+ context 'with two activerecord connection pools' do
186
+ before :each do
187
+ class Model1 < ActiveRecord::Base
188
+ end
189
+
190
+ class Model2 < ActiveRecord::Base
191
+ end
192
+
193
+ Model1.establish_connection(config)
194
+ Model2.establish_connection(config)
195
+ end
196
+
197
+ it 'should not leak raw connection into activerecord pool' do
198
+ # checkout a connection from Model1 pool and remove from the pool
199
+ conn = Model1.connection_pool.checkout
200
+ Model1.connection_pool.remove(conn)
201
+
202
+ # assign the connection to Model2 pool
203
+ conn.pool=Model2.connection_pool
204
+
205
+ # now close the connection to return it back to the pool
206
+ conn.close
207
+
208
+ # checkout the connection and make sure it is still a makara proxy
209
+ expect(Model2.connection).to eq(conn)
210
+ end
211
+
212
+ it 'should be able to steal the connection from a different thread' do
213
+ conn = Model1.connection_pool.checkout
214
+ conn.steal!
215
+ expect(conn.owner).to eq(Thread.current)
216
+ # steal! is not thread safe. it should be done while holding connection pool's mutex
217
+ t = Thread.new { conn.steal! }
218
+ t.join
219
+ expect(conn.owner).to eq(t)
220
+ end
221
+
222
+ it 'should not be able to expire the connection from same thread' do
223
+ conn = Model2.connection_pool.checkout
224
+ # expire is not thread safe. it should be done while holding connection pool's mutex
225
+ expect {
226
+ t = Thread.new { conn.expire }
227
+ t.join
228
+ }.to raise_error(ActiveRecord::ActiveRecordError)
229
+ end
230
+
231
+ it 'should be able to checkin connection back into activerecord pool' do
232
+ conn = Model1.connection_pool.checkout
233
+ Model1.connection_pool.checkin(conn)
234
+ # checkout the connection again and make sure it is same connection
235
+ expect(Model1.connection).to eq(conn)
236
+ end
237
+ end
194
238
  end
data/spec/cache_spec.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Makara::Cache do
4
-
5
4
  it 'shows a warning' do
6
5
  expect(Makara::Logging::Logger).to receive(:log).with(/Setting the Makara::Cache\.store won't have any effects/, :warn)
7
6
  described_class.store = :noop
@@ -1,21 +1,20 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Makara::ConfigParser do
4
-
5
4
  let(:config){
6
5
  {
7
- :top_level => 'value',
8
- :makara => {
9
- :connections => [
6
+ top_level: 'value',
7
+ makara: {
8
+ connections: [
10
9
  {
11
- :role => 'master',
12
- :name => 'themaster'
10
+ role: 'master',
11
+ name: 'themaster'
13
12
  },
14
13
  {
15
- :name => 'slave1'
14
+ name: 'slave1'
16
15
  },
17
16
  {
18
- :name => 'slave2'
17
+ name: 'slave2'
19
18
  }
20
19
  ]
21
20
  }
@@ -25,27 +24,27 @@ describe Makara::ConfigParser do
25
24
  context '::merge_and_resolve_default_url_config' do
26
25
  let(:config_without_url) do
27
26
  {
28
- :master_ttl => 5,
29
- :blacklist_duration => 30,
30
- :sticky => true,
31
- :adapter => 'mysql2_makara',
32
- :encoding => 'utf8',
33
- :host => 'localhost',
34
- :database => 'db_name',
35
- :username => 'db_username',
36
- :password => 'db_password',
37
- :port => 3306
27
+ master_ttl: 5,
28
+ blacklist_duration: 30,
29
+ sticky: true,
30
+ adapter: 'mysql2_makara',
31
+ encoding: 'utf8',
32
+ host: 'localhost',
33
+ database: 'db_name',
34
+ username: 'db_username',
35
+ password: 'db_password',
36
+ port: 3306
38
37
  }
39
38
  end
40
39
 
41
40
  let(:config_with_url) do
42
41
  {
43
- :master_ttl => 5,
44
- :blacklist_duration => 30,
45
- :sticky => true,
46
- :adapter => 'mysql2_makara',
47
- :encoding => 'utf8',
48
- :url => 'mysql2://db_username:db_password@localhost:3306/db_name'
42
+ master_ttl: 5,
43
+ blacklist_duration: 30,
44
+ sticky: true,
45
+ adapter: 'mysql2_makara',
46
+ encoding: 'utf8',
47
+ url: 'mysql2://db_username:db_password@localhost:3306/db_name'
49
48
  }
50
49
  end
51
50
 
@@ -76,12 +75,11 @@ describe Makara::ConfigParser do
76
75
  ENV['DATABASE_URL'] = database_url
77
76
  end
78
77
  end
79
-
80
78
  end
81
79
 
82
80
  it 'should provide a default proxy id based on the recursively sorted config' do
83
81
  parsera = described_class.new(config)
84
- parserb = described_class.new(config.merge(:other => 'value'))
82
+ parserb = described_class.new(config.merge(other: 'value'))
85
83
  parserc = described_class.new(config)
86
84
 
87
85
  expect(parsera.id).not_to eq(parserb.id)
@@ -113,27 +111,27 @@ describe Makara::ConfigParser do
113
111
  parser = described_class.new(config)
114
112
  expect(parser.master_configs).to eq([
115
113
  {
116
- :name => 'themaster',
117
- :top_level => 'value',
118
- :sticky => true,
119
- :blacklist_duration => 30,
120
- :master_ttl => 5
114
+ name: 'themaster',
115
+ top_level: 'value',
116
+ sticky: true,
117
+ blacklist_duration: 30,
118
+ master_ttl: 5
121
119
  }
122
120
  ])
123
121
  expect(parser.slave_configs).to eq([
124
122
  {
125
- :name => 'slave1',
126
- :top_level => 'value',
127
- :sticky => true,
128
- :blacklist_duration => 30,
129
- :master_ttl => 5
123
+ name: 'slave1',
124
+ top_level: 'value',
125
+ sticky: true,
126
+ blacklist_duration: 30,
127
+ master_ttl: 5
130
128
  },
131
129
  {
132
- :name => 'slave2',
133
- :top_level => 'value',
134
- :sticky => true,
135
- :blacklist_duration => 30,
136
- :master_ttl => 5
130
+ name: 'slave2',
131
+ top_level: 'value',
132
+ sticky: true,
133
+ blacklist_duration: 30,
134
+ master_ttl: 5
137
135
  }
138
136
  ])
139
137
  end
@@ -146,27 +144,27 @@ describe Makara::ConfigParser do
146
144
  parser = described_class.new(config)
147
145
  expect(parser.master_configs).to eq([
148
146
  {
149
- :name => 'themaster',
150
- :top_level => 'value',
151
- :sticky => true,
152
- :blacklist_duration => 456,
153
- :master_ttl => 5
147
+ name: 'themaster',
148
+ top_level: 'value',
149
+ sticky: true,
150
+ blacklist_duration: 456,
151
+ master_ttl: 5
154
152
  }
155
153
  ])
156
154
  expect(parser.slave_configs).to eq([
157
155
  {
158
- :name => 'slave1',
159
- :top_level => 'slave value',
160
- :sticky => true,
161
- :blacklist_duration => 123,
162
- :master_ttl => 5
156
+ name: 'slave1',
157
+ top_level: 'slave value',
158
+ sticky: true,
159
+ blacklist_duration: 123,
160
+ master_ttl: 5
163
161
  },
164
162
  {
165
- :name => 'slave2',
166
- :top_level => 'value',
167
- :sticky => true,
168
- :blacklist_duration => 123,
169
- :master_ttl => 5
163
+ name: 'slave2',
164
+ top_level: 'value',
165
+ sticky: true,
166
+ blacklist_duration: 123,
167
+ master_ttl: 5
170
168
  }
171
169
  ])
172
170
  end
@@ -1,8 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Makara::ConnectionWrapper do
4
-
5
- let(:proxy){ FakeProxy.new({:makara => {:blacklist_duration => 5, :connections => [{:role => 'master'}, {:role => 'slave'}, {:role => 'slave'}]}}) }
4
+ let(:proxy){ FakeProxy.new({makara: {blacklist_duration: 5, connections: [{role: 'master'}, {role: 'slave'}, {role: 'slave'}]}}) }
6
5
  let(:connection){ subject._makara_connection }
7
6
 
8
7
  subject{ proxy.master_pool.connections.first }
data/spec/cookie_spec.rb CHANGED
@@ -53,20 +53,20 @@ describe Makara::Cookie do
53
53
  Makara::Cookie.store(context_data, headers)
54
54
 
55
55
  expect(headers['Set-Cookie']).to include("#{cookie_key}=mysql%3A#{(now + 5).to_f}%7Credis%3A#{(now + 5).to_f};")
56
- expect(headers['Set-Cookie']).to include("path=/; max-age=10; expires=#{(Time.now + 10).gmtime.rfc2822}; HttpOnly")
56
+ expect(headers['Set-Cookie']).to include("path=/; max-age=10; expires=#{(Time.now + 10).httpdate}; HttpOnly")
57
57
  end
58
58
 
59
59
  it 'expires the cookie if the next context is empty' do
60
60
  Makara::Cookie.store({}, headers)
61
61
 
62
- expect(headers['Set-Cookie']).to eq("#{cookie_key}=; path=/; max-age=0; expires=#{Time.now.gmtime.rfc2822}; HttpOnly")
62
+ expect(headers['Set-Cookie']).to eq("#{cookie_key}=; path=/; max-age=0; expires=#{Time.now.httpdate}; HttpOnly")
63
63
  end
64
64
 
65
65
  it 'allows custom cookie options to be provided' do
66
- Makara::Cookie.store(context_data, headers, { :secure => true })
66
+ Makara::Cookie.store(context_data, headers, { secure: true })
67
67
 
68
68
  expect(headers['Set-Cookie']).to include("#{cookie_key}=mysql%3A#{(now + 5).to_f}%7Credis%3A#{(now + 5).to_f};")
69
- expect(headers['Set-Cookie']).to include("path=/; max-age=10; expires=#{(Time.now + 10).gmtime.rfc2822}; secure; HttpOnly")
69
+ expect(headers['Set-Cookie']).to include("path=/; max-age=10; expires=#{(Time.now + 10).httpdate}; secure; HttpOnly")
70
70
  end
71
71
  end
72
72
  end
@@ -12,7 +12,7 @@ describe Makara::Middleware do
12
12
 
13
13
  let(:env){ {} }
14
14
  let(:proxy){ FakeProxy.new(config(1,2)) }
15
- let(:middleware){ described_class.new(app, :secure => true) }
15
+ let(:middleware){ described_class.new(app, secure: true) }
16
16
 
17
17
  let(:key){ Makara::Cookie::IDENTIFIER }
18
18
 
@@ -49,7 +49,7 @@ describe Makara::Middleware do
49
49
 
50
50
  _, headers, body = middleware.call(env)
51
51
 
52
- expect(headers['Set-Cookie']).to eq("#{key}=mock_mysql%3A#{(now + 5).to_f}; path=/; max-age=10; expires=#{(Time.now + 10).gmtime.rfc2822}; secure; HttpOnly")
52
+ expect(headers['Set-Cookie']).to eq("#{key}=mock_mysql%3A#{(now + 5).to_f}; path=/; max-age=10; expires=#{(Time.now + 10).httpdate}; secure; HttpOnly")
53
53
  expect(body).to eq('master/1')
54
54
  end
55
55
  end
data/spec/pool_spec.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Makara::Pool do
4
-
5
- let(:proxy){ FakeProxy.new({:makara => pool_config.merge(:connections => [])}) }
4
+ let(:proxy){ FakeProxy.new({makara: pool_config.merge(connections: [])}) }
6
5
  let(:pool){ Makara::Pool.new('test', proxy) }
7
- let(:pool_config){ {:blacklist_duration => 5} }
6
+ let(:pool_config){ {blacklist_duration: 5} }
7
+ let(:master_pool){ Makara::Pool.new('master', proxy) }
8
8
 
9
9
  it 'should wrap connections with a ConnectionWrapper as theyre added to the pool' do
10
10
  expect(pool.connections).to be_empty
@@ -12,7 +12,7 @@ describe Makara::Pool do
12
12
  connection_a = FakeConnection.new(something: 'a')
13
13
 
14
14
  wrapper_a = pool.add(pool_config){ connection_a }
15
- wrapper_b = pool.add(pool_config.merge(:weight => 2)){ FakeConnection.new }
15
+ wrapper_b = pool.add(pool_config.merge(weight: 2)){ FakeConnection.new }
16
16
 
17
17
  connections = pool.connections
18
18
  weighted_connections = pool.strategy.instance_variable_get("@weighted_connections")
@@ -28,7 +28,6 @@ describe Makara::Pool do
28
28
  end
29
29
 
30
30
  it 'should determine if its completely blacklisted' do
31
-
32
31
  pool.add(pool_config){ FakeConnection.new }
33
32
  pool.add(pool_config){ FakeConnection.new }
34
33
 
@@ -40,7 +39,6 @@ describe Makara::Pool do
40
39
  end
41
40
 
42
41
  it 'sends methods to all underlying objects if asked to' do
43
-
44
42
  a = FakeConnection.new
45
43
  b = FakeConnection.new
46
44
 
@@ -51,11 +49,9 @@ describe Makara::Pool do
51
49
  expect(b).to receive(:query).with('test').once
52
50
 
53
51
  pool.send_to_all :query, 'test'
54
-
55
52
  end
56
53
 
57
54
  it 'only sends methods to underlying objects which are not blacklisted' do
58
-
59
55
  a = FakeConnection.new
60
56
  b = FakeConnection.new
61
57
  c = FakeConnection.new
@@ -71,11 +67,9 @@ describe Makara::Pool do
71
67
  wrapper_c._makara_blacklist!
72
68
 
73
69
  pool.send_to_all :query, 'test'
74
-
75
70
  end
76
71
 
77
72
  it 'provides the next connection and blacklists' do
78
-
79
73
  connection_a = FakeConnection.new(something: 'a')
80
74
  connection_b = FakeConnection.new(something: 'b')
81
75
 
@@ -95,7 +89,6 @@ describe Makara::Pool do
95
89
  expect(wrapper_a._makara_blacklisted?).to eq(false)
96
90
  expect(wrapper_b._makara_blacklisted?).to eq(false)
97
91
  end
98
-
99
92
  end
100
93
 
101
94
  it 'provides the same connection if the context has not changed and the proxy is sticky' do
@@ -125,7 +118,6 @@ describe Makara::Pool do
125
118
  end
126
119
 
127
120
  it 'raises an error when all connections are blacklisted' do
128
-
129
121
  wrapper_a = pool.add(pool_config.dup){ FakeConnection.new }
130
122
  wrapper_b = pool.add(pool_config.dup){ FakeConnection.new }
131
123
 
@@ -134,7 +126,6 @@ describe Makara::Pool do
134
126
 
135
127
  allow(pool).to receive(:next).and_return(wrapper_a, wrapper_b, nil)
136
128
 
137
-
138
129
  begin
139
130
  pool.provide do |connection|
140
131
  raise Makara::Errors::BlacklistConnection.new(connection, StandardError.new('failure'))
@@ -146,7 +137,6 @@ describe Makara::Pool do
146
137
  end
147
138
 
148
139
  it 'skips blacklisted connections when choosing the next one' do
149
-
150
140
  pool.add(pool_config){ FakeConnection.new }
151
141
  pool.add(pool_config){ FakeConnection.new }
152
142
 
@@ -154,7 +144,28 @@ describe Makara::Pool do
154
144
  wrapper_b._makara_blacklist!
155
145
 
156
146
  10.times{ pool.provide{|connection| expect(connection).not_to eq(wrapper_b) } }
147
+ end
157
148
 
149
+ it 'should error out while blacklisted in transaction' do
150
+ wrapper_a = master_pool.add(pool_config){ FakeConnection.new(open_transactions: 1) }
151
+ master_pool.add(pool_config){ FakeConnection.new }
152
+ expect {
153
+ master_pool.provide do |connection|
154
+ if connection == wrapper_a
155
+ raise Makara::Errors::BlacklistConnection.new(wrapper_a, StandardError.new('failure'))
156
+ end
157
+ end
158
+ }.to raise_error(Makara::Errors::BlacklistedWhileInTransaction)
158
159
  end
159
160
 
161
+ it 'skips blacklisted connections in master pool when not in transaction' do
162
+ wrapper_a = master_pool.add(pool_config){ FakeConnection.new(open_transactions: 0) }
163
+ master_pool.add(pool_config){ FakeConnection.new }
164
+ master_pool.provide do |connection|
165
+ if connection == wrapper_a
166
+ raise Makara::Errors::BlacklistConnection.new(wrapper_a, StandardError.new('failure'))
167
+ end
168
+ end
169
+ 10.times{ master_pool.provide{|connection| expect(connection).not_to eq(wrapper_a) } }
170
+ end
160
171
  end
data/spec/proxy_spec.rb CHANGED
@@ -1,10 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Makara::Proxy do
4
-
5
4
  let(:klass){ FakeProxy }
6
5
 
7
-
8
6
  it 'sets up a master and slave pool no matter the number of connections' do
9
7
  proxy = klass.new(config(0, 0))
10
8
  expect(proxy.master_pool).to be_a(Makara::Pool)
@@ -23,7 +21,6 @@ describe Makara::Proxy do
23
21
  expect(proxy.slave_pool).to be_a(Makara::Pool)
24
22
  end
25
23
 
26
-
27
24
  it 'instantiates N connections within each pool' do
28
25
  proxy = klass.new(config(1, 2))
29
26
 
@@ -89,7 +86,6 @@ describe Makara::Proxy do
89
86
  end
90
87
  end
91
88
 
92
-
93
89
  describe '#appropriate_pool' do
94
90
  let(:proxy) { klass.new(config(1,1)) }
95
91
 
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'uri'
1
2
  require 'active_record'
2
3
  require 'makara'
3
4
  require 'timecop'
@@ -5,7 +6,7 @@ require 'yaml'
5
6
  require 'rack'
6
7
 
7
8
  begin
8
- require 'byebug'
9
+ require 'pry'
9
10
  rescue LoadError
10
11
  end
11
12
 
@@ -14,6 +15,10 @@ begin
14
15
  rescue LoadError
15
16
  end
16
17
 
18
+ if RUBY_VERSION >= "2.7.0"
19
+ Warning[:deprecated] = true
20
+ end
21
+
17
22
  RSpec.configure do |config|
18
23
  config.run_all_when_everything_filtered = true
19
24
  config.filter_run :focus
@@ -1,10 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Makara::Strategies::PriorityFailover do
4
- let(:proxy){ FakeProxy.new({:makara => pool_config.merge(makara_config).merge(:connections => [])}) }
4
+ let(:proxy){ FakeProxy.new({makara: pool_config.merge(makara_config).merge(connections: [])}) }
5
5
  let(:pool){ Makara::Pool.new('master', proxy) }
6
- let(:pool_config){ {:blacklist_duration => 5} }
7
- let(:makara_config) { { :master_strategy => 'failover' } }
6
+ let(:pool_config){ {blacklist_duration: 5} }
7
+ let(:makara_config) { { master_strategy: 'failover' } }
8
8
  let(:strategy) { pool.strategy }
9
9
 
10
10
  it 'should use the strategy' do
@@ -45,5 +45,4 @@ describe Makara::Strategies::PriorityFailover do
45
45
  expect(strategy.current.something).to eql('b')
46
46
  expect(strategy.next.something).to eql('b')
47
47
  end
48
-
49
48
  end