makara 0.4.1 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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