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
@@ -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 }
@@ -14,8 +13,11 @@ describe Makara::ConnectionWrapper do
14
13
  end
15
14
 
16
15
  it 'should invoke hijacked methods on the proxy when invoked directly' do
17
- expect(proxy).to receive(:execute).with('test').once
18
- connection.execute("test")
16
+ expect(proxy).to receive(:execute).with('test').once do |&block|
17
+ expect(block.call).to eq('Hello')
18
+ end
19
+
20
+ connection.execute('test') { 'Hello' }
19
21
  end
20
22
 
21
23
  it 'should have a default weight of 1' do
data/spec/context_spec.rb CHANGED
@@ -1,146 +1,209 @@
1
1
  require 'spec_helper'
2
+ require 'rack'
3
+ require 'time'
2
4
 
3
5
  describe Makara::Context do
6
+ let(:now) { Time.parse('2018-02-11 11:10:40 +0000') }
7
+ let(:context_data) { { "mysql" => now.to_f + 5, "redis" => now.to_f + 5 } }
4
8
 
5
- describe 'get_current' do
6
- it 'does not share context acorss threads' do
7
- uniq_curret_contexts = []
8
- threads = []
9
-
10
- 1.upto(3).map do |i|
11
- threads << Thread.new do
12
- current = Makara::Context.get_current
13
- expect(current).to_not be_nil
14
- expect(uniq_curret_contexts).to_not include(current)
15
- uniq_curret_contexts << current
16
-
17
- sleep(0.2)
18
- end
19
- sleep(0.1)
20
- end
9
+ before do
10
+ Timecop.freeze(now)
11
+ end
12
+
13
+ after do
14
+ Timecop.return
15
+ end
16
+
17
+ it 'does not share stickiness state across threads' do
18
+ contexts = {}
19
+ threads = []
20
+
21
+ [1, -1].each_with_index do |f, i|
22
+ threads << Thread.new do
23
+ context_data = { "mysql" => now.to_f + f*5 }
24
+ Makara::Context.set_current(context_data)
21
25
 
22
- threads.map(&:join)
23
- expect(uniq_curret_contexts.uniq.count).to eq(3)
26
+ contexts["context_#{i}"] = Makara::Context.stuck?('mysql')
27
+
28
+ sleep(0.2)
29
+ end
30
+ sleep(0.1)
24
31
  end
32
+
33
+ threads.map(&:join)
34
+ expect(contexts).to eq({ 'context_0' => true, 'context_1' => false })
25
35
  end
26
36
 
27
37
  describe 'set_current' do
38
+ it 'sets stickiness information from given hash' do
39
+ Makara::Context.set_current(context_data)
40
+
41
+ expect(Makara::Context.stuck?('mysql')).to be_truthy
42
+ expect(Makara::Context.stuck?('redis')).to be_truthy
43
+ expect(Makara::Context.stuck?('mariadb')).to be_falsey
44
+ end
45
+ end
28
46
 
29
- it 'does not share context acorss threads' do
30
- uniq_curret_contexts = []
31
- threads = []
47
+ describe 'stick' do
48
+ before do
49
+ Makara::Context.set_current(context_data)
50
+ end
51
+
52
+ it 'sticks a proxy to master for the current request' do
53
+ expect(Makara::Context.stuck?('mariadb')).to be_falsey
32
54
 
33
- 1.upto(3).map do |i|
34
- threads << Thread.new do
55
+ Makara::Context.stick('mariadb', 10)
35
56
 
36
- current = Makara::Context.set_current("val#{i}")
37
- expect(current).to_not be_nil
38
- expect(current).to eq("val#{i}")
57
+ expect(Makara::Context.stuck?('mariadb')).to be_truthy
58
+ Timecop.travel(Time.now + 20)
59
+ # The ttl kicks off when the context is committed
60
+ next_context = Makara::Context.next
61
+ expect(next_context['mariadb']).to be >= now.to_f + 30 # 10 ttl + 20 seconds that have passed
39
62
 
40
- sleep(0.2)
63
+ # It expires after going to the next request
64
+ Timecop.travel(Time.now + 20)
65
+ Makara::Context.next
66
+ expect(Makara::Context.stuck?('mariadb')).to be_falsey
67
+ end
41
68
 
42
- current = Makara::Context.get_current
43
- expect(current).to_not be_nil
44
- expect(current).to eq("val#{i}")
69
+ it "doesn't overwrite previously stuck proxies with current-request-only stickiness" do
70
+ expect(Makara::Context.stuck?('mysql')).to be_truthy
45
71
 
46
- uniq_curret_contexts << current
47
- end
48
- sleep(0.1)
49
- end
72
+ # ttl=0 to avoid persisting mysql for the next request
73
+ Makara::Context.stick('mysql', 0)
50
74
 
51
- threads.map(&:join)
52
- expect(uniq_curret_contexts.uniq.count).to eq(3)
75
+ Makara::Context.next
76
+ # mysql proxy is still stuck in the next context
77
+ expect(Makara::Context.stuck?('mysql')).to be_truthy
53
78
  end
54
- end
55
79
 
56
- describe 'get_previous' do
57
- it 'does not share context acorss threads' do
58
- uniq_curret_contexts = []
59
- threads = []
60
-
61
- 1.upto(3).map do |i|
62
- threads << Thread.new do
63
- current = Makara::Context.get_previous
64
- expect(current).to_not be_nil
65
- expect(uniq_curret_contexts).to_not include(current)
66
- uniq_curret_contexts << current
67
-
68
- sleep(0.2)
69
- end
70
- sleep(0.1)
71
- end
80
+ it 'uses always the max ttl given' do
81
+ expect(Makara::Context.stuck?('mariadb')).to be_falsey
82
+
83
+ Makara::Context.stick('mariadb', 10)
84
+ expect(Makara::Context.stuck?('mariadb')).to be_truthy
85
+
86
+ Makara::Context.stick('mariadb', 5)
87
+
88
+ next_context = Makara::Context.next
89
+ expect(next_context['mariadb']).to eq((now + 10).to_f)
90
+ end
91
+
92
+ it 'supports floats as ttl' do
93
+ expect(Makara::Context.stuck?('mariadb')).to be_falsey
72
94
 
73
- threads.map(&:join)
74
- expect(uniq_curret_contexts.uniq.count).to eq(3)
95
+ Makara::Context.stick('mariadb', 0.5)
96
+
97
+ next_context = Makara::Context.next
98
+ expect(next_context['mariadb']).to eq((now + 0.5).to_f)
75
99
  end
76
100
  end
77
101
 
78
- describe 'set_previous' do
79
- it 'does not share context acorss threads' do
80
- uniq_curret_contexts = []
81
- threads = []
102
+ describe 'next' do
103
+ before do
104
+ Makara::Context.set_current(context_data)
105
+ end
82
106
 
83
- 1.upto(3).map do |i|
84
- threads << Thread.new do
107
+ it 'returns nil if there is nothing new to stick' do
108
+ expect(Makara::Context.next).to be_nil
109
+ end
85
110
 
86
- current = Makara::Context.set_previous("val#{i}")
87
- expect(current).to_not be_nil
88
- expect(current).to eq("val#{i}")
111
+ it "doesn't store staged proxies with 0 stickiness duration" do
112
+ Makara::Context.stick('mariadb', 0)
89
113
 
90
- sleep(0.2)
114
+ expect(Makara::Context.next).to be_nil
115
+ end
91
116
 
92
- current = Makara::Context.get_previous
93
- expect(current).to_not be_nil
94
- expect(current).to eq("val#{i}")
117
+ it 'returns hash with updated stickiness' do
118
+ Makara::Context.stick('mariadb', 10)
95
119
 
96
- uniq_curret_contexts << current
97
- end
98
- sleep(0.1)
99
- end
120
+ next_context = Makara::Context.next
121
+ expect(next_context['mysql']).to eq((now + 5).to_f)
122
+ expect(next_context['redis']).to eq((now + 5).to_f)
123
+ expect(next_context['mariadb']).to eq((now + 10).to_f)
124
+ end
125
+
126
+ it "doesn't update previously stored proxies if the update will cause a sooner expiration" do
127
+ Makara::Context.stick('mariadb', 10)
128
+ Makara::Context.stick('mysql', 2.5)
129
+
130
+ next_context = Makara::Context.next
131
+ expect(next_context['mysql']).to eq((now + 5).to_f)
132
+ expect(next_context['mariadb']).to eq((now + 10).to_f)
133
+
134
+ Makara::Context.set_current(context_data)
135
+ Makara::Context.stick('mysql', 2.5)
136
+
137
+ expect(Makara::Context.next).to be_nil
138
+ end
139
+
140
+ it 'clears expired entries for proxies that are no longer stuck' do
141
+ Timecop.travel(now + 10)
100
142
 
101
- threads.map(&:join)
102
- expect(uniq_curret_contexts.uniq.count).to eq(3)
143
+ expect(Makara::Context.next).to eq({})
103
144
  end
104
145
 
105
- it 'clears config sticky cache' do
106
- Makara::Cache.store = :memory
146
+ it 'sets expiration time with ttl based on the invokation time' do
147
+ Makara::Context.stick('mariadb', 10)
148
+ request_ends_at = Time.now + 20
149
+ Timecop.travel(request_ends_at)
107
150
 
108
- Makara::Context.set_previous('a')
109
- Makara::Context.stick('a', 1, 10)
110
- expect(Makara::Context.previously_stuck?(1)).to be_truthy
151
+ next_context = Makara::Context.next
111
152
 
112
- Makara::Context.set_previous('b')
113
- expect(Makara::Context.previously_stuck?(1)).to be_falsey
153
+ # The previous stuck proxies would have expired
154
+ expect(next_context['mysql']).to be_nil
155
+ expect(next_context['redis']).to be_nil
156
+ # But the proxy stuck in that request would expire in ttl seconds from now
157
+ expect(next_context['mariadb']).to be >= (request_ends_at + 10).to_f
114
158
  end
115
159
  end
116
160
 
117
- describe 'stick' do
118
- it 'sticks a config to master for subsequent requests' do
119
- Makara::Cache.store = :memory
161
+ describe 'release' do
162
+ before do
163
+ Makara::Context.set_current(context_data)
164
+ end
165
+
166
+ it 'clears stickiness for the given proxy' do
167
+ expect(Makara::Context.stuck?('mysql')).to be_truthy
168
+
169
+ Makara::Context.release('mysql')
170
+
171
+ expect(Makara::Context.stuck?('mysql')).to be_falsey
172
+
173
+ next_context = Makara::Context.next
174
+ expect(next_context.key?('mysql')).to be_falsey
175
+ expect(next_context['redis']).to eq((now + 5).to_f)
176
+ end
177
+
178
+ it 'does nothing if the proxy given was not stuck' do
179
+ expect(Makara::Context.stuck?('mariadb')).to be_falsey
120
180
 
121
- expect(Makara::Context.stuck?('context', 1)).to be_falsey
181
+ Makara::Context.release('mariadb')
122
182
 
123
- Makara::Context.stick('context', 1, 10)
124
- expect(Makara::Context.stuck?('context', 1)).to be_truthy
125
- expect(Makara::Context.stuck?('context', 2)).to be_falsey
183
+ expect(Makara::Context.stuck?('mariadb')).to be_falsey
184
+ expect(Makara::Context.next).to be_nil
126
185
  end
127
186
  end
128
187
 
129
- describe 'previously_stuck?' do
130
- it 'checks whether a config was stuck to master in the previous context' do
131
- Makara::Cache.store = :memory
132
- Makara::Context.set_previous 'previous'
188
+ describe 'release_all' do
189
+ it 'clears stickiness for all stuck proxies' do
190
+ Makara::Context.set_current(context_data)
191
+ expect(Makara::Context.stuck?('mysql')).to be_truthy
192
+ expect(Makara::Context.stuck?('redis')).to be_truthy
193
+
194
+ Makara::Context.release_all
133
195
 
134
- # Emulate sticking the previous web request to master.
135
- Makara::Context.stick 'previous', 1, 10
196
+ expect(Makara::Context.stuck?('mysql')).to be_falsey
197
+ expect(Makara::Context.stuck?('redis')).to be_falsey
198
+ expect(Makara::Context.next).to eq({})
199
+ end
200
+
201
+ it 'does nothing if there were no stuck proxies' do
202
+ Makara::Context.set_current({})
136
203
 
137
- # Emulate handling the subsequent web request with a previous context
138
- # cookie that is stuck to master.
139
- expect(Makara::Context.previously_stuck?(1)).to be_truthy
204
+ Makara::Context.release_all
140
205
 
141
- # Other configs should not be stuck to master, though.
142
- expect(Makara::Context.previously_stuck?(2)).to be_falsey
206
+ expect(Makara::Context.next).to be_nil
143
207
  end
144
208
  end
145
209
  end
146
-
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ require 'rack'
3
+ require 'time'
4
+
5
+ describe Makara::Cookie do
6
+ let(:now) { Time.parse('2018-02-11 11:10:40 +0000') }
7
+ let(:cookie_key) { Makara::Cookie::IDENTIFIER }
8
+
9
+ before do
10
+ Timecop.freeze(now)
11
+ end
12
+
13
+ after do
14
+ Timecop.return
15
+ end
16
+
17
+ describe 'fetch' do
18
+ let(:cookie_string) { "mysql:#{now.to_f + 5}|redis:#{now.to_f + 5}" }
19
+ let(:request) { Rack::Request.new('HTTP_COOKIE' => "#{cookie_key}=#{cookie_string}") }
20
+
21
+ it 'parses stickiness context from cookie string' do
22
+ context_data = Makara::Cookie.fetch(request)
23
+
24
+ expect(context_data['mysql']).to eq(now.to_f + 5)
25
+ expect(context_data['redis']).to eq(now.to_f + 5)
26
+ expect(context_data.key?('mariadb')).to be_falsey
27
+ end
28
+
29
+ it 'returns empty context data when there is no cookie' do
30
+ context_data = Makara::Cookie.fetch(Rack::Request.new('HTTP_COOKIE' => "another_cookie=1"))
31
+
32
+ expect(context_data).to eq({})
33
+ end
34
+
35
+ it 'returns empty context data when the cookie contents are invalid' do
36
+ context_data = Makara::Cookie.fetch(Rack::Request.new('HTTP_COOKIE' => "#{cookie_key}=1"))
37
+
38
+ expect(context_data).to eq({})
39
+ end
40
+ end
41
+
42
+ describe 'store' do
43
+ let(:headers) { {} }
44
+ let(:context_data) { { "mysql" => now.to_f + 5, "redis" => now.to_f + 5 } }
45
+
46
+ it 'does not set a cookie if there is no next context' do
47
+ Makara::Cookie.store(nil, headers)
48
+
49
+ expect(headers).to eq({})
50
+ end
51
+
52
+ it 'sets the context cookie with updated stickiness and enough expiration time' do
53
+ Makara::Cookie.store(context_data, headers)
54
+
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).httpdate}; HttpOnly")
57
+ end
58
+
59
+ it 'expires the cookie if the next context is empty' do
60
+ Makara::Cookie.store({}, headers)
61
+
62
+ expect(headers['Set-Cookie']).to eq("#{cookie_key}=; path=/; max-age=0; expires=#{Time.now.httpdate}; HttpOnly")
63
+ end
64
+
65
+ it 'allows custom cookie options to be provided' do
66
+ Makara::Cookie.store(context_data, headers, { secure: true })
67
+
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).httpdate}; secure; HttpOnly")
70
+ end
71
+ end
72
+ end
@@ -1,84 +1,55 @@
1
1
  require 'spec_helper'
2
+ require 'time'
2
3
 
3
4
  describe Makara::Middleware do
4
-
5
+ let(:now) { Time.parse('2018-02-11 11:10:40 +0000') }
5
6
  let(:app){
6
7
  lambda{|env|
7
- proxy.query(env[:query] || 'select * from users')
8
- [200, {}, ["#{Makara::Context.get_current}-#{Makara::Context.get_previous}"]]
8
+ response = proxy.query(env[:query] || 'select * from users')
9
+ [200, {}, response]
9
10
  }
10
11
  }
11
12
 
12
13
  let(:env){ {} }
13
14
  let(:proxy){ FakeProxy.new(config(1,2)) }
14
- let(:middleware){ described_class.new(app, :secure => true) }
15
-
16
- let(:key){ Makara::Middleware::IDENTIFIER }
17
-
18
- it 'should set the context before the request' do
19
- Makara::Context.set_previous 'old'
20
- Makara::Context.set_current 'old'
15
+ let(:middleware){ described_class.new(app, secure: true) }
21
16
 
22
- response = middleware.call(env)
23
- current, prev = context_from(response)
17
+ let(:key){ Makara::Cookie::IDENTIFIER }
24
18
 
25
- expect(current).not_to eq('old')
26
- expect(prev).not_to eq('old')
27
-
28
- expect(current).to eq(Makara::Context.get_current)
29
- expect(prev).to eq(Makara::Context.get_previous)
19
+ before do
20
+ @hijacked_methods = FakeProxy.hijack_methods
21
+ FakeProxy.hijack_method :query
22
+ Timecop.freeze(now)
30
23
  end
31
24
 
32
- it 'should use the cookie-provided context if present' do
33
- env['HTTP_COOKIE'] = "#{key}=abcdefg--200; path=/; max-age=5"
25
+ after do
26
+ Timecop.return
27
+ FakeProxy.hijack_methods = []
28
+ FakeProxy.hijack_method(*@hijacked_methods)
29
+ end
34
30
 
35
- response = middleware.call(env)
36
- current, prev = context_from(response)
31
+ it 'should init the context and not be stuck by default' do
32
+ _, headers, body = middleware.call(env)
37
33
 
38
- expect(prev).to eq('abcdefg')
39
- expect(current).to eq(Makara::Context.get_current)
40
- expect(current).not_to eq('abcdefg')
34
+ expect(headers).to eq({})
35
+ expect(body).to eq('slave/1')
41
36
  end
42
37
 
43
- it 'should use the param-provided context if present' do
44
- env['QUERY_STRING'] = "dog=true&#{key}=abcdefg&cat=false"
38
+ it 'should use the cookie-provided context if present' do
39
+ env['HTTP_COOKIE'] = "#{key}=mock_mysql%3A#{(now + 3).to_f}; path=/; max-age=5"
45
40
 
46
- response = middleware.call(env)
47
- current, prev = context_from(response)
41
+ _, headers, body = middleware.call(env)
48
42
 
49
- expect(prev).to eq('abcdefg')
50
- expect(current).to eq(Makara::Context.get_current)
51
- expect(current).not_to eq('abcdefg')
43
+ expect(headers).to eq({})
44
+ expect(body).to eq('master/1')
52
45
  end
53
46
 
54
47
  it 'should set the cookie if master is used' do
55
48
  env[:query] = 'update users set name = "phil"'
56
49
 
57
- status, headers, body = middleware.call(env)
50
+ _, headers, body = middleware.call(env)
58
51
 
59
- expect(headers['Set-Cookie']).to eq("#{key}=#{Makara::Context.get_current}--200; path=/; max-age=5; 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
+ expect(body).to eq('master/1')
60
54
  end
61
-
62
- it 'should preserve the same context if the previous request was a redirect' do
63
- env['HTTP_COOKIE'] = "#{key}=abcdefg--301; path=/; max-age=5"
64
-
65
- response = middleware.call(env)
66
- curr, prev = context_from(response)
67
-
68
- expect(curr).to eq('abcdefg')
69
- expect(prev).to eq('abcdefg')
70
-
71
- env['HTTP_COOKIE'] = response[1]['Set-Cookie']
72
-
73
- response = middleware.call(env)
74
- curr2, prev2 = context_from(response)
75
-
76
- expect(prev2).to eq('abcdefg')
77
- expect(curr2).to eq(Makara::Context.get_current)
78
- end
79
-
80
- def context_from(response)
81
- response[2][0].split('-')
82
- end
83
-
84
55
  end