makara 0.3.9 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) 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 +88 -32
  9. data/Gemfile +1 -16
  10. data/README.md +39 -35
  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 +111 -33
  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.rb +14 -5
  27. data/lib/makara/cache.rb +4 -42
  28. data/lib/makara/config_parser.rb +18 -16
  29. data/lib/makara/connection_wrapper.rb +43 -22
  30. data/lib/makara/context.rb +108 -37
  31. data/lib/makara/cookie.rb +53 -0
  32. data/lib/makara/error_handler.rb +2 -11
  33. data/lib/makara/errors/all_connections_blacklisted.rb +0 -2
  34. data/lib/makara/errors/blacklist_connection.rb +0 -2
  35. data/lib/makara/errors/blacklisted_while_in_transaction.rb +12 -0
  36. data/lib/makara/errors/invalid_shard.rb +14 -0
  37. data/lib/makara/errors/makara_error.rb +0 -1
  38. data/lib/makara/errors/no_connections_available.rb +0 -2
  39. data/lib/makara/logging/logger.rb +1 -5
  40. data/lib/makara/logging/subscriber.rb +0 -2
  41. data/lib/makara/middleware.rb +12 -76
  42. data/lib/makara/pool.rb +55 -47
  43. data/lib/makara/proxy.rb +76 -56
  44. data/lib/makara/railtie.rb +0 -8
  45. data/lib/makara/strategies/abstract.rb +1 -0
  46. data/lib/makara/strategies/priority_failover.rb +2 -0
  47. data/lib/makara/strategies/round_robin.rb +7 -3
  48. data/lib/makara/strategies/shard_aware.rb +45 -0
  49. data/lib/makara/version.rb +2 -4
  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 +10 -14
  53. data/spec/active_record/connection_adapters/makara_mysql2_adapter_spec.rb +18 -16
  54. data/spec/active_record/connection_adapters/makara_postgis_adapter_spec.rb +6 -9
  55. data/spec/active_record/connection_adapters/makara_postgresql_adapter_spec.rb +70 -10
  56. data/spec/cache_spec.rb +2 -53
  57. data/spec/config_parser_spec.rb +75 -57
  58. data/spec/connection_wrapper_spec.rb +6 -4
  59. data/spec/context_spec.rb +163 -100
  60. data/spec/cookie_spec.rb +72 -0
  61. data/spec/middleware_spec.rb +27 -56
  62. data/spec/pool_spec.rb +25 -14
  63. data/spec/proxy_spec.rb +50 -39
  64. data/spec/spec_helper.rb +10 -10
  65. data/spec/strategies/priority_failover_spec.rb +3 -4
  66. data/spec/strategies/round_robin_spec.rb +4 -8
  67. data/spec/strategies/shard_aware_spec.rb +218 -0
  68. data/spec/support/deep_dup.rb +1 -1
  69. data/spec/support/helpers.rb +10 -6
  70. data/spec/support/mock_objects.rb +6 -5
  71. data/spec/support/mysql2_database.yml +3 -2
  72. data/spec/support/mysql2_database_with_custom_errors.yml +6 -1
  73. data/spec/support/pool_extensions.rb +0 -3
  74. data/spec/support/postgis_database.yml +2 -0
  75. data/spec/support/postgis_schema.rb +6 -3
  76. data/spec/support/postgresql_database.yml +2 -2
  77. data/spec/support/proxy_extensions.rb +1 -3
  78. data/spec/support/schema.rb +6 -6
  79. data/spec/support/user.rb +4 -0
  80. metadata +170 -22
  81. data/.travis.yml +0 -70
  82. data/gemfiles/ar-head.gemfile +0 -15
  83. data/gemfiles/ar30.gemfile +0 -32
  84. data/gemfiles/ar31.gemfile +0 -31
  85. data/gemfiles/ar32.gemfile +0 -31
  86. data/gemfiles/ar40.gemfile +0 -17
  87. data/gemfiles/ar41.gemfile +0 -17
  88. data/gemfiles/ar42.gemfile +0 -17
  89. data/gemfiles/ar50.gemfile +0 -15
  90. data/gemfiles/ar51.gemfile +0 -15
  91. data/lib/makara/cache/memory_store.rb +0 -28
  92. data/lib/makara/cache/noop_store.rb +0 -15
@@ -2,7 +2,6 @@ require 'spec_helper'
2
2
  require 'active_record/connection_adapters/makara_abstract_adapter'
3
3
 
4
4
  describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter::ErrorHandler do
5
-
6
5
  let(:handler){ described_class.new }
7
6
  let(:proxy) { FakeAdapter.new(config(1,1)) }
8
7
  let(:connection){ proxy.master_pool.connections.first }
@@ -60,9 +59,8 @@ describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter::ErrorHandler d
60
59
  end
61
60
 
62
61
  describe 'custom errors' do
63
-
64
62
  let(:config_path) { File.join(File.expand_path('../../../', __FILE__), 'support', 'mysql2_database_with_custom_errors.yml') }
65
- let(:config) { YAML.load_file(config_path)['test'] }
63
+ let(:config) { YAML.load(ERB.new(File.read(config_path)).result)['test'] }
66
64
  let(:handler){ described_class.new }
67
65
  let(:proxy) { FakeAdapter.new(config) }
68
66
  let(:connection){ proxy.master_pool.connections.first }
@@ -85,8 +83,5 @@ describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter::ErrorHandler d
85
83
  end
86
84
  }.to raise_error(Makara::Errors::BlacklistConnection)
87
85
  end
88
-
89
86
  end
90
-
91
-
92
87
  end
@@ -2,7 +2,6 @@ require 'spec_helper'
2
2
  require 'active_record/connection_adapters/makara_abstract_adapter'
3
3
 
4
4
  describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter do
5
-
6
5
  let(:klass){ FakeAdapter }
7
6
 
8
7
  {
@@ -27,17 +26,23 @@ describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter do
27
26
  ' select * from users for update' => true,
28
27
  'select * from users lock in share mode' => true,
29
28
  'select * from users where name = "for update"' => false,
30
- 'select * from users where name = "lock in share mode"' => false
29
+ 'select * from users where name = "lock in share mode"' => false,
30
+ 'select nextval(\'users_id_seq\')' => true,
31
+ 'select currval(\'users_id_seq\')' => true,
32
+ 'select lastval()' => true,
33
+ 'with fence as (select * from users) select * from fence' => false,
34
+ 'with fence as (select * from felines) insert to cats' => true,
35
+ 'select get_lock(\'foo\', 0)' => true,
36
+ 'select release_lock(\'foo\')' => true,
37
+ 'select pg_advisory_lock(12345)' => true,
38
+ 'select pg_advisory_unlock(12345)' => true
31
39
  }.each do |sql, should_go_to_master|
32
-
33
40
  it "determines that \"#{sql}\" #{should_go_to_master ? 'requires' : 'does not require'} master" do
34
41
  proxy = klass.new(config(1,1))
35
42
  expect(proxy.master_for?(sql)).to eq(should_go_to_master)
36
43
  end
37
-
38
44
  end
39
45
 
40
-
41
46
  {
42
47
  "SET @@things" => true,
43
48
  "INSERT INTO wisdom ('The truth will set you free.')" => false,
@@ -52,7 +57,6 @@ describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter do
52
57
  max_treats IS NULL
53
58
  } => false
54
59
  }.each do |sql, should_send_to_all_connections|
55
-
56
60
  it "determines that \"#{sql}\" #{should_send_to_all_connections ? 'should' : 'should not'} be sent to all underlying connections" do
57
61
  proxy = klass.new(config(1,1))
58
62
  proxy.master_pool.connections.each{|con| expect(con).to receive(:execute).with(sql).once}
@@ -65,12 +69,7 @@ describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter do
65
69
  end
66
70
 
67
71
  proxy.execute(sql)
68
-
69
- if should_send_to_all_connections
70
- expect(proxy.master_context).to be_nil
71
- end
72
72
  end
73
-
74
73
  end
75
74
 
76
75
  {
@@ -103,12 +102,9 @@ describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter do
103
102
  max_treats IS NULL
104
103
  } => true
105
104
  }.each do |sql,should_stick|
106
-
107
105
  it "should #{should_stick ? 'stick' : 'not stick'} to master if handling sql like \"#{sql}\"" do
108
106
  proxy = klass.new(config(0,0))
109
107
  expect(proxy.would_stick?(sql)).to eq(should_stick)
110
108
  end
111
-
112
109
  end
113
-
114
110
  end
@@ -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
@@ -82,10 +78,9 @@ describe 'MakaraMysql2Adapter' do
82
78
  ActiveRecord::Base.connection
83
79
 
84
80
  load(File.dirname(__FILE__) + '/../../support/schema.rb')
85
- Makara::Context.set_current Makara::Context.generate
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)
@@ -150,7 +142,7 @@ describe 'MakaraMysql2Adapter' do
150
142
 
151
143
  it 'should send reads to the slave' do
152
144
  # ensure the next connection will be the first one
153
- connection.slave_pool.strategy.instance_variable_set('@current_idx', connection.slave_pool.connections.length)
145
+ allow_any_instance_of(Makara::Strategies::RoundRobin).to receive(:single_one?){ true }
154
146
 
155
147
  con = connection.slave_pool.connections.first
156
148
  expect(con).to receive(:execute).with('SELECT * FROM users').once
@@ -158,6 +150,18 @@ describe 'MakaraMysql2Adapter' do
158
150
  connection.execute('SELECT * FROM users')
159
151
  end
160
152
 
153
+ it 'should send exists? to slave' do
154
+ allow_any_instance_of(Makara::Strategies::RoundRobin).to receive(:single_one?){ true }
155
+ Test::User.exists? # flush other (schema) things that need to happen
156
+
157
+ con = connection.slave_pool.connections.first
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
+
162
+ Test::User.exists?
163
+ end
164
+
161
165
  it 'should send writes to master' do
162
166
  con = connection.master_pool.connections.first
163
167
  expect(con).to receive(:execute).with('UPDATE users SET name = "bob" WHERE id = 1')
@@ -183,7 +187,6 @@ describe 'MakaraMysql2Adapter' do
183
187
  }.to raise_error(Makara::Errors::AllConnectionsBlacklisted)
184
188
  end
185
189
  end
186
-
187
190
  end
188
191
 
189
192
  describe 'transaction support' do
@@ -241,5 +244,4 @@ describe 'MakaraMysql2Adapter' do
241
244
  it_behaves_like 'a transaction supporter'
242
245
  end
243
246
  end
244
-
245
247
  end
@@ -1,5 +1,9 @@
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
+
4
+ require 'active_record'
5
+
6
+ # TODO: test this in AR 5+ ?
3
7
  if RUBY_ENGINE == 'ruby' &&
4
8
  ActiveRecord::VERSION::MAJOR == 4 &&
5
9
  ActiveRecord::VERSION::MINOR >= 2
@@ -10,12 +14,8 @@ if RUBY_ENGINE == 'ruby' &&
10
14
  require 'active_record/connection_adapters/postgis_adapter'
11
15
 
12
16
  describe 'MakaraPostgisAdapter' do
13
- let(:db_username){ ENV['TRAVIS'] ? 'postgres' : `whoami`.chomp }
14
-
15
17
  let(:config) do
16
- base = YAML.load_file(File.expand_path('spec/support/postgis_database.yml'))['test']
17
- base['username'] = db_username
18
- base
18
+ YAML.load_file(File.expand_path('spec/support/postgis_database.yml'))['test']
19
19
  end
20
20
 
21
21
  let(:connection) { ActiveRecord::Base.connection }
@@ -83,10 +83,7 @@ if RUBY_ENGINE == 'ruby' &&
83
83
 
84
84
  it 'should send reads to the slave' do
85
85
  # ensure the next connection will be the first one
86
- connection.slave_pool
87
- .strategy
88
- .instance_variable_set('@current_idx',
89
- connection.slave_pool.connections.length)
86
+ allow_any_instance_of(Makara::Strategies::RoundRobin).to receive(:single_one?){ true }
90
87
 
91
88
  con = connection.slave_pool.connections.first
92
89
  expect(con).to receive(:execute).with('SELECT * FROM users').once
@@ -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)
@@ -64,7 +57,7 @@ describe 'MakaraPostgreSQLAdapter' do
64
57
 
65
58
  it 'should send reads to the slave' do
66
59
  # ensure the next connection will be the first one
67
- connection.slave_pool.strategy.instance_variable_set('@current_idx', connection.slave_pool.connections.length)
60
+ allow_any_instance_of(Makara::Strategies::RoundRobin).to receive(:single_one?){ true }
68
61
 
69
62
  con = connection.slave_pool.connections.first
70
63
  expect(con).to receive(:execute).with('SELECT * FROM users').once
@@ -72,6 +65,19 @@ describe 'MakaraPostgreSQLAdapter' do
72
65
  connection.execute('SELECT * FROM users')
73
66
  end
74
67
 
68
+ it 'should send exists? to slave' do
69
+ allow_any_instance_of(Makara::Strategies::RoundRobin).to receive(:single_one?){ true }
70
+ Test::User.exists? # flush other (schema) things that need to happen
71
+
72
+ con = connection.slave_pool.connections.first
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
+
78
+ Test::User.exists?
79
+ end
80
+
75
81
  it 'should send writes to master' do
76
82
  con = connection.master_pool.connections.first
77
83
  expect(con).to receive(:execute).with('UPDATE users SET name = "bob" WHERE id = 1')
@@ -175,4 +181,58 @@ describe 'MakaraPostgreSQLAdapter' do
175
181
  it_behaves_like 'a transaction supporter'
176
182
  end
177
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
178
238
  end
data/spec/cache_spec.rb CHANGED
@@ -1,59 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Makara::Cache do
4
-
5
- it 'should not require a store be set' do
6
- described_class.store = nil
7
-
8
- expect(
9
- described_class.send(:store)
10
- ).to be_nil
11
-
12
- expect{
13
- described_class.read('test')
14
- }.not_to raise_error
15
- end
16
-
17
- it 'provides a few stores for testing purposes' do
18
- described_class.store = :memory
19
- described_class.write('test', 'value', 10)
20
- expect(described_class.read('test')).to eq('value')
21
-
4
+ it 'shows a warning' do
5
+ expect(Makara::Logging::Logger).to receive(:log).with(/Setting the Makara::Cache\.store won't have any effects/, :warn)
22
6
  described_class.store = :noop
23
- described_class.write('test', 'value', 10)
24
- expect(described_class.read('test')).to be_nil
25
- end
26
-
27
-
28
- # this will be used in tests so we have to ensure this works as expected
29
- context Makara::Cache::MemoryStore do
30
-
31
- let(:store){ Makara::Cache::MemoryStore.new }
32
- let(:data){ store.instance_variable_get('@data') }
33
-
34
- it 'should read and write keys' do
35
- expect(store.read('test')).to be_nil
36
- store.write('test', 'value')
37
- expect(store.read('test')).to eq('value')
38
- end
39
-
40
- it 'provides time based expiration' do
41
- store.write('test', 'value', :expires_in => 5)
42
- expect(store.read('test')).to eq('value')
43
-
44
- Timecop.travel Time.now + 6 do
45
- expect(store.read('test')).to be_nil
46
- end
47
- end
48
-
49
- it 'cleans the data' do
50
- store.write('test', 'value', :expires_in => -5)
51
- expect(store.read('test')).to be_nil
52
- expect(data).not_to have_key('test')
53
- end
54
-
55
7
  end
56
-
57
-
58
-
59
8
  end
@@ -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,44 +75,63 @@ describe Makara::ConfigParser do
76
75
  ENV['DATABASE_URL'] = database_url
77
76
  end
78
77
  end
79
-
80
78
  end
81
79
 
82
- it 'should provide an id based on the recursively sorted config' do
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)
88
86
  expect(parsera.id).to eq(parserc.id)
89
87
  end
90
88
 
89
+ it 'should use provided proxy id instead of default' do
90
+ config_with_custom_id = config.dup
91
+ config_with_custom_id[:makara][:id] = 'my_proxy'
92
+
93
+ parser = described_class.new(config_with_custom_id)
94
+
95
+ expect(parser.id).to eq('my_proxy')
96
+ end
97
+
98
+ it 'should replace reserved characters and show a warning for provided proxy ids' do
99
+ config_with_custom_id = config.dup
100
+ config_with_custom_id[:makara][:id] = "my|proxy|id:with:reserved:characters"
101
+ warning = "Proxy id 'my|proxy|id:with:reserved:characters' changed to 'myproxyidwithreservedcharacters'"
102
+ expect(Makara::Logging::Logger).to receive(:log).with(warning, :warn)
103
+
104
+ parser = described_class.new(config_with_custom_id)
105
+
106
+ expect(parser.id).to eq('myproxyidwithreservedcharacters')
107
+ end
108
+
91
109
  context 'master and slave configs' do
92
110
  it 'should provide master and slave configs' do
93
111
  parser = described_class.new(config)
94
112
  expect(parser.master_configs).to eq([
95
113
  {
96
- :name => 'themaster',
97
- :top_level => 'value',
98
- :sticky => true,
99
- :blacklist_duration => 30,
100
- :master_ttl => 5
114
+ name: 'themaster',
115
+ top_level: 'value',
116
+ sticky: true,
117
+ blacklist_duration: 30,
118
+ master_ttl: 5
101
119
  }
102
120
  ])
103
121
  expect(parser.slave_configs).to eq([
104
122
  {
105
- :name => 'slave1',
106
- :top_level => 'value',
107
- :sticky => true,
108
- :blacklist_duration => 30,
109
- :master_ttl => 5
123
+ name: 'slave1',
124
+ top_level: 'value',
125
+ sticky: true,
126
+ blacklist_duration: 30,
127
+ master_ttl: 5
110
128
  },
111
129
  {
112
- :name => 'slave2',
113
- :top_level => 'value',
114
- :sticky => true,
115
- :blacklist_duration => 30,
116
- :master_ttl => 5
130
+ name: 'slave2',
131
+ top_level: 'value',
132
+ sticky: true,
133
+ blacklist_duration: 30,
134
+ master_ttl: 5
117
135
  }
118
136
  ])
119
137
  end
@@ -126,27 +144,27 @@ describe Makara::ConfigParser do
126
144
  parser = described_class.new(config)
127
145
  expect(parser.master_configs).to eq([
128
146
  {
129
- :name => 'themaster',
130
- :top_level => 'value',
131
- :sticky => true,
132
- :blacklist_duration => 456,
133
- :master_ttl => 5
147
+ name: 'themaster',
148
+ top_level: 'value',
149
+ sticky: true,
150
+ blacklist_duration: 456,
151
+ master_ttl: 5
134
152
  }
135
153
  ])
136
154
  expect(parser.slave_configs).to eq([
137
155
  {
138
- :name => 'slave1',
139
- :top_level => 'slave value',
140
- :sticky => true,
141
- :blacklist_duration => 123,
142
- :master_ttl => 5
156
+ name: 'slave1',
157
+ top_level: 'slave value',
158
+ sticky: true,
159
+ blacklist_duration: 123,
160
+ master_ttl: 5
143
161
  },
144
162
  {
145
- :name => 'slave2',
146
- :top_level => 'value',
147
- :sticky => true,
148
- :blacklist_duration => 123,
149
- :master_ttl => 5
163
+ name: 'slave2',
164
+ top_level: 'value',
165
+ sticky: true,
166
+ blacklist_duration: 123,
167
+ master_ttl: 5
150
168
  }
151
169
  ])
152
170
  end