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.
- checksums.yaml +5 -5
- data/.github/dependabot.yml +11 -0
- data/.github/workflows/CI.yml +88 -0
- data/.github/workflows/gem-publish-public.yml +36 -0
- data/.rspec +1 -1
- data/.rubocop.yml +15 -0
- data/.rubocop_todo.yml +670 -0
- data/CHANGELOG.md +69 -48
- data/Gemfile +1 -16
- data/README.md +8 -9
- data/Rakefile +1 -1
- data/gemfiles/activerecord_5.2.gemfile +8 -0
- data/gemfiles/activerecord_6.0.gemfile +8 -0
- data/gemfiles/activerecord_6.1.gemfile +8 -0
- data/gemfiles/activerecord_head.gemfile +6 -0
- data/lib/active_record/connection_adapters/jdbcmysql_makara_adapter.rb +4 -18
- data/lib/active_record/connection_adapters/jdbcpostgresql_makara_adapter.rb +4 -18
- data/lib/active_record/connection_adapters/makara_abstract_adapter.rb +107 -30
- data/lib/active_record/connection_adapters/makara_jdbcmysql_adapter.rb +4 -18
- data/lib/active_record/connection_adapters/makara_jdbcpostgresql_adapter.rb +4 -18
- data/lib/active_record/connection_adapters/makara_mysql2_adapter.rb +4 -20
- data/lib/active_record/connection_adapters/makara_postgis_adapter.rb +4 -19
- data/lib/active_record/connection_adapters/makara_postgresql_adapter.rb +4 -20
- data/lib/active_record/connection_adapters/mysql2_makara_adapter.rb +4 -20
- data/lib/active_record/connection_adapters/postgresql_makara_adapter.rb +4 -20
- data/lib/makara/cache.rb +0 -2
- data/lib/makara/config_parser.rb +7 -15
- data/lib/makara/connection_wrapper.rb +43 -22
- data/lib/makara/context.rb +1 -0
- data/lib/makara/cookie.rb +1 -0
- data/lib/makara/error_handler.rb +0 -9
- data/lib/makara/errors/all_connections_blacklisted.rb +0 -2
- data/lib/makara/errors/blacklist_connection.rb +0 -2
- data/lib/makara/errors/blacklisted_while_in_transaction.rb +12 -0
- data/lib/makara/errors/invalid_shard.rb +14 -0
- data/lib/makara/errors/makara_error.rb +0 -1
- data/lib/makara/errors/no_connections_available.rb +0 -2
- data/lib/makara/logging/logger.rb +0 -4
- data/lib/makara/logging/subscriber.rb +0 -2
- data/lib/makara/middleware.rb +1 -2
- data/lib/makara/pool.rb +49 -31
- data/lib/makara/proxy.rb +56 -30
- data/lib/makara/railtie.rb +0 -2
- data/lib/makara/strategies/abstract.rb +1 -0
- data/lib/makara/strategies/priority_failover.rb +2 -0
- data/lib/makara/strategies/round_robin.rb +1 -3
- data/lib/makara/strategies/shard_aware.rb +45 -0
- data/lib/makara/version.rb +1 -3
- data/lib/makara.rb +7 -6
- data/makara.gemspec +26 -3
- data/spec/active_record/connection_adapters/makara_abstract_adapter_error_handling_spec.rb +1 -6
- data/spec/active_record/connection_adapters/makara_abstract_adapter_spec.rb +0 -9
- data/spec/active_record/connection_adapters/makara_mysql2_adapter_spec.rb +9 -22
- data/spec/active_record/connection_adapters/makara_postgis_adapter_spec.rb +2 -10
- data/spec/active_record/connection_adapters/makara_postgresql_adapter_spec.rb +62 -18
- data/spec/cache_spec.rb +0 -1
- data/spec/config_parser_spec.rb +54 -56
- data/spec/connection_wrapper_spec.rb +1 -2
- data/spec/cookie_spec.rb +4 -4
- data/spec/middleware_spec.rb +2 -2
- data/spec/pool_spec.rb +25 -14
- data/spec/proxy_spec.rb +0 -4
- data/spec/spec_helper.rb +6 -1
- data/spec/strategies/priority_failover_spec.rb +3 -4
- data/spec/strategies/round_robin_spec.rb +4 -8
- data/spec/strategies/shard_aware_spec.rb +218 -0
- data/spec/support/deep_dup.rb +1 -1
- data/spec/support/helpers.rb +5 -5
- data/spec/support/mock_objects.rb +5 -4
- data/spec/support/mysql2_database.yml +2 -2
- data/spec/support/mysql2_database_with_custom_errors.yml +2 -2
- data/spec/support/pool_extensions.rb +0 -3
- data/spec/support/postgis_schema.rb +1 -1
- data/spec/support/postgresql_database.yml +0 -2
- data/spec/support/proxy_extensions.rb +1 -3
- data/spec/support/schema.rb +1 -1
- data/spec/support/user.rb +1 -2
- metadata +165 -20
- data/.travis.yml +0 -105
- data/gemfiles/ar-head.gemfile +0 -24
- data/gemfiles/ar30.gemfile +0 -36
- data/gemfiles/ar31.gemfile +0 -36
- data/gemfiles/ar32.gemfile +0 -36
- data/gemfiles/ar40.gemfile +0 -24
- data/gemfiles/ar41.gemfile +0 -24
- data/gemfiles/ar42.gemfile +0 -24
- data/gemfiles/ar50.gemfile +0 -24
- 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
|
-
|
10
|
-
|
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
|
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
|
-
|
169
|
-
expect(
|
170
|
-
|
171
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
83
|
-
|
84
|
-
expect(
|
85
|
-
|
86
|
-
|
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
data/spec/config_parser_spec.rb
CHANGED
@@ -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
|
-
:
|
8
|
-
:
|
9
|
-
:
|
6
|
+
top_level: 'value',
|
7
|
+
makara: {
|
8
|
+
connections: [
|
10
9
|
{
|
11
|
-
:
|
12
|
-
:
|
10
|
+
role: 'master',
|
11
|
+
name: 'themaster'
|
13
12
|
},
|
14
13
|
{
|
15
|
-
:
|
14
|
+
name: 'slave1'
|
16
15
|
},
|
17
16
|
{
|
18
|
-
:
|
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
|
-
:
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
33
|
-
:
|
34
|
-
:
|
35
|
-
:
|
36
|
-
:
|
37
|
-
:
|
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
|
-
:
|
44
|
-
:
|
45
|
-
:
|
46
|
-
:
|
47
|
-
:
|
48
|
-
:
|
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(:
|
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
|
-
:
|
117
|
-
:
|
118
|
-
:
|
119
|
-
:
|
120
|
-
:
|
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
|
-
:
|
126
|
-
:
|
127
|
-
:
|
128
|
-
:
|
129
|
-
:
|
123
|
+
name: 'slave1',
|
124
|
+
top_level: 'value',
|
125
|
+
sticky: true,
|
126
|
+
blacklist_duration: 30,
|
127
|
+
master_ttl: 5
|
130
128
|
},
|
131
129
|
{
|
132
|
-
:
|
133
|
-
:
|
134
|
-
:
|
135
|
-
:
|
136
|
-
:
|
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
|
-
:
|
150
|
-
:
|
151
|
-
:
|
152
|
-
:
|
153
|
-
:
|
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
|
-
:
|
159
|
-
:
|
160
|
-
:
|
161
|
-
:
|
162
|
-
:
|
156
|
+
name: 'slave1',
|
157
|
+
top_level: 'slave value',
|
158
|
+
sticky: true,
|
159
|
+
blacklist_duration: 123,
|
160
|
+
master_ttl: 5
|
163
161
|
},
|
164
162
|
{
|
165
|
-
:
|
166
|
-
:
|
167
|
-
:
|
168
|
-
:
|
169
|
-
:
|
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).
|
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.
|
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, { :
|
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).
|
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
|
data/spec/middleware_spec.rb
CHANGED
@@ -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, :
|
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).
|
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){ {:
|
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(:
|
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 '
|
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({:
|
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){ {:
|
7
|
-
let(:makara_config) { { :
|
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
|