makara 0.3.7 → 0.3.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d07deed98a5cc668ea6621fe741b4fbbcb210e9b
4
- data.tar.gz: 1f849bf4f2eb6a38c5a6253ed64348e9d60e76cd
3
+ metadata.gz: a43f7871351a95b0291a4624bdfded3e1e4bccf3
4
+ data.tar.gz: feaf04905d1a7293abd47cf32a0f69f23575c609
5
5
  SHA512:
6
- metadata.gz: 837a1140206708c09ca4ba72f3febe76d00ebc9e10161c114f7ca80d6f749476d9b8bd0b5e4505394c9229d80a12c7c973967e1430dd42c2038b4b236c21d531
7
- data.tar.gz: 21dca3b441fae6bb6f438566e3e2d5d2fa0acfa7e0637475f26215486277b225805206200b5c3150f6ac79cc17ae8f0bcfd379feb1e090ec25f3d6aee996d1a9
6
+ metadata.gz: 06ce4185196b043f4129039a18a55db3f18816ab8af517372193ac28e2cf8517b4dd0abee9970ab012b0a0f2214fd56e42fcd3fce5643d077a8aa3537bbd4635
7
+ data.tar.gz: a45e25f35d71242f954d4a5fdeafeb0907399b496d19c9122e227ad04bd0486986ce37e2390877f191a2adc0e7295a37ecade58278c57991b57f6152da3123b1
data/.travis.yml CHANGED
@@ -1,8 +1,22 @@
1
+ sudo: false
1
2
  language: ruby
3
+ cache: bundler
4
+
5
+ services:
6
+ - mysql
7
+ - postgresql
8
+
9
+ before_script:
10
+ - mysql -e 'create database makara_test;'
11
+ - psql -c 'create database makara_test;' -U postgres
2
12
 
3
13
  rvm:
4
- - 2.0.0
5
- - 2.1.1
14
+ - 2.0
15
+ - 2.1
16
+ - 2.2
17
+ - 2.3
18
+ - 2.4
19
+ - ruby-head
6
20
  - jruby
7
21
 
8
22
  gemfile:
@@ -12,17 +26,44 @@ gemfile:
12
26
  - gemfiles/ar40.gemfile
13
27
  - gemfiles/ar41.gemfile
14
28
  - gemfiles/ar42.gemfile
29
+ - gemfiles/ar50.gemfile
30
+ - gemfiles/ar51.gemfile
31
+ - gemfiles/ar-head.gemfile
15
32
 
16
- sudo: false
17
-
18
- services:
19
- - mysql
20
- - postgresql
21
-
22
- before_script:
23
- - mysql -e 'create database makara_test;'
24
- - psql -c 'create database makara_test;' -U postgres
33
+ env:
34
+ global:
35
+ - "JRUBY_OPTS='--dev -J-Xmx1024M'"
25
36
 
26
- before_install:
27
- - gem update --system 2.1.11
28
- - gem --version
37
+ matrix:
38
+ exclude:
39
+ - gemfile: gemfiles/ar30.gemfile
40
+ rvm: 2.2
41
+ - gemfile: gemfiles/ar30.gemfile
42
+ rvm: 2.3
43
+ - gemfile: gemfiles/ar30.gemfile
44
+ rvm: 2.4
45
+ - gemfile: gemfiles/ar30.gemfile
46
+ rvm: ruby-head
47
+ - gemfile: gemfiles/ar50.gemfile
48
+ rvm: 2.0
49
+ - gemfile: gemfiles/ar50.gemfile
50
+ rvm: 2.1
51
+ - gemfile: gemfiles/ar50.gemfile
52
+ rvm: 2.2
53
+ - gemfile: gemfiles/ar51.gemfile
54
+ rvm: 2.0
55
+ - gemfile: gemfiles/ar51.gemfile
56
+ rvm: 2.1
57
+ - gemfile: gemfiles/ar51.gemfile
58
+ rvm: 2.2
59
+ - gemfile: gemfiles/ar-head.gemfile
60
+ rvm: 2.0
61
+ - gemfile: gemfiles/ar-head.gemfile
62
+ rvm: 2.1
63
+ - gemfile: gemfiles/ar-head.gemfile
64
+ rvm: 2.2
65
+ allow_failures:
66
+ - gemfile: gemfiles/ar-head.gemfile
67
+ - rvm: ruby-head
68
+ - rvm: jruby
69
+ fast_finish: true
data/CHANGELOG.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
- ## v0.3.7.rc - 2016-09-16
4
+ ## v0.3.7 - 2016-09-22
5
5
 
6
- [Full Changelog](https://github.com/taskrabbit/makara/compare/v0.3.6...v0.3.7.rc)
6
+ [Full Changelog](https://github.com/taskrabbit/makara/compare/v0.3.6...v0.3.7)
7
7
 
8
8
  Changed
9
9
 
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in makara.gemspec
4
+ gemspec :path => '../'
5
+
6
+
7
+ gem 'rake'
8
+ gem 'activerecord', :git => 'https://github.com/rails/rails'
9
+ gem 'rspec'
10
+ gem 'rack'
11
+ gem 'timecop'
12
+ gem 'mysql2', :platform => :ruby
13
+ gem 'activerecord-jdbcmysql-adapter', :platform => :jruby
14
+ gem 'pg', :platform => :ruby
15
+ gem 'activerecord-jdbcpostgresql-adapter', :platform => :jruby
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in makara.gemspec
4
+ gemspec :path => '../'
5
+
6
+
7
+ gem 'rake'
8
+ gem 'activerecord', '~> 5.0.0'
9
+ gem 'rspec'
10
+ gem 'rack'
11
+ gem 'timecop'
12
+ gem 'mysql2', :platform => :ruby
13
+ gem 'activerecord-jdbcmysql-adapter', :platform => :jruby
14
+ gem 'pg', :platform => :ruby
15
+ gem 'activerecord-jdbcpostgresql-adapter', :platform => :jruby
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in makara.gemspec
4
+ gemspec :path => '../'
5
+
6
+
7
+ gem 'rake'
8
+ gem 'activerecord', '~> 5.1.0'
9
+ gem 'rspec'
10
+ gem 'rack'
11
+ gem 'timecop'
12
+ gem 'mysql2', :platform => :ruby
13
+ gem 'activerecord-jdbcmysql-adapter', :platform => :jruby
14
+ gem 'pg', :platform => :ruby
15
+ gem 'activerecord-jdbcpostgresql-adapter', :platform => :jruby
@@ -165,27 +165,36 @@ module ActiveRecord
165
165
 
166
166
 
167
167
  def should_stick?(method_name, args)
168
- sql = args.first.to_s
168
+ sql = coerce_query_to_sql_string(args.first)
169
169
  return false if sql_skip_stickiness_matchers.any?{|m| sql =~ m }
170
170
  super
171
171
  end
172
172
 
173
173
 
174
174
  def needed_by_all?(method_name, args)
175
- sql = args.first.to_s
175
+ sql = coerce_query_to_sql_string(args.first)
176
176
  return true if sql_all_matchers.any?{|m| sql =~ m }
177
177
  false
178
178
  end
179
179
 
180
180
 
181
181
  def needs_master?(method_name, args)
182
- sql = args.first.to_s
182
+ sql = coerce_query_to_sql_string(args.first)
183
183
  return true if sql_master_matchers.any?{|m| sql =~ m }
184
184
  return false if sql_slave_matchers.any?{|m| sql =~ m }
185
185
  true
186
186
  end
187
187
 
188
188
 
189
+ def coerce_query_to_sql_string(sql_or_arel)
190
+ if sql_or_arel.respond_to?(:to_sql)
191
+ sql_or_arel.to_sql
192
+ else
193
+ sql_or_arel.to_s
194
+ end
195
+ end
196
+
197
+
189
198
  def connection_for(config)
190
199
  config = Makara::ConfigParser.merge_and_resolve_default_url_config(config)
191
200
  active_record_connection_for(config)
data/lib/makara.rb CHANGED
@@ -12,6 +12,7 @@ module Makara
12
12
  autoload :Proxy, 'makara/proxy'
13
13
 
14
14
  module Errors
15
+ autoload :MakaraError, 'makara/errors/makara_error'
15
16
  autoload :AllConnectionsBlacklisted, 'makara/errors/all_connections_blacklisted'
16
17
  autoload :BlacklistConnection, 'makara/errors/blacklist_connection'
17
18
  autoload :NoConnectionsAvailable, 'makara/errors/no_connections_available'
@@ -37,7 +37,7 @@ module Makara
37
37
 
38
38
  # has this node been blacklisted?
39
39
  def _makara_blacklisted?
40
- @blacklisted_until.to_i > Time.now.to_i
40
+ @blacklisted_until.present? && @blacklisted_until.to_i > Time.now.to_i
41
41
  end
42
42
 
43
43
  # blacklist this node for @config[:blacklist_duration] seconds
@@ -13,32 +13,69 @@ module Makara
13
13
  end
14
14
 
15
15
  def get_previous
16
- get_current_thread_local_for(:makara_context_previous)
16
+ fetch(:makara_context_previous) { generate }
17
17
  end
18
18
 
19
19
  def set_previous(context)
20
- set_current_thread_local(:makara_context_previous,context)
20
+ previously_sticky.clear
21
+ set(:makara_context_previous,context)
21
22
  end
22
23
 
23
24
  def get_current
24
- get_current_thread_local_for(:makara_context_current)
25
+ fetch(:makara_context_current) { generate }
25
26
  end
26
27
 
27
28
  def set_current(context)
28
- set_current_thread_local(:makara_context_current,context)
29
+ set(:makara_context_current,context)
30
+ end
31
+
32
+ def previously_stuck?(config_id)
33
+ previously_sticky.fetch(config_id) do
34
+ stuck?(Makara::Context.get_previous, config_id)
35
+ end
36
+ end
37
+
38
+ # Called by `Proxy#stick_to_master!` to stick subsequent requests to
39
+ # master. They'll see the current context as their previous context
40
+ # when they're asking whether they should be stuck to master.
41
+ def stick(context, config_id, ttl)
42
+ Makara::Cache.write(cache_key_for(context, config_id), '1', ttl)
43
+ end
44
+
45
+ def stuck?(context, config_id)
46
+ !!Makara::Cache.read(cache_key_for(context, config_id))
29
47
  end
30
48
 
31
49
  protected
32
50
 
33
- def get_current_thread_local_for(type)
34
- t = Thread.current
35
- current = t.respond_to?(:thread_variable_get) ? t.thread_variable_get(type) : t[type]
36
- current ||= set_current_thread_local(type,generate)
51
+ def previously_sticky
52
+ fetch(:makara_previously_sticky) { Hash.new }
37
53
  end
38
54
 
39
- def set_current_thread_local(type,context)
40
- t = Thread.current
41
- t.respond_to?(:thread_variable_set) ? t.thread_variable_set(type,context) : t[type]=context
55
+ def cache_key_for(context, config_id)
56
+ "makara::#{context}-#{config_id}"
57
+ end
58
+
59
+ def fetch(key)
60
+ get(key) || set(key,yield)
61
+ end
62
+
63
+ if Thread.current.respond_to?(:thread_variable_get)
64
+ def get(key)
65
+ Thread.current.thread_variable_get(key)
66
+ end
67
+
68
+ def set(key,value)
69
+ Thread.current.thread_variable_set(key,value)
70
+ end
71
+ else
72
+ def get(key)
73
+ Thread.current[key]
74
+ end
75
+
76
+ def set(key,value)
77
+ Thread.current[key]=value
78
+ end
42
79
  end
43
80
 
44
81
  end
@@ -11,7 +11,7 @@ module Makara
11
11
 
12
12
  rescue Exception => e
13
13
 
14
- if e.class.name =~ /^Makara::/
14
+ if e.is_a?(Makara::Errors::MakaraError)
15
15
  harshly(e)
16
16
  else
17
17
  gracefully(connection, e)
@@ -1,6 +1,6 @@
1
1
  module Makara
2
2
  module Errors
3
- class AllConnectionsBlacklisted < StandardError
3
+ class AllConnectionsBlacklisted < MakaraError
4
4
 
5
5
  def initialize(pool, errors)
6
6
  errors = [*errors]
@@ -1,6 +1,6 @@
1
1
  module Makara
2
2
  module Errors
3
- class BlacklistConnection < ::StandardError
3
+ class BlacklistConnection < MakaraError
4
4
 
5
5
  attr_reader :original_error
6
6
 
@@ -0,0 +1,7 @@
1
+ module Makara
2
+ module Errors
3
+ class MakaraError < ::ActiveRecord::ActiveRecordError
4
+
5
+ end
6
+ end
7
+ end
@@ -1,6 +1,6 @@
1
1
  module Makara
2
2
  module Errors
3
- class NoConnectionsAvailable < ::StandardError
3
+ class NoConnectionsAvailable < MakaraError
4
4
 
5
5
  attr_reader :role
6
6
 
@@ -10,9 +10,15 @@ module Makara
10
10
 
11
11
  IDENTIFIER = '_mkra_ctxt'
12
12
 
13
+ DEFAULT_COOKIE = {
14
+ :path => '/',
15
+ :http_only => true,
16
+ :max_age => '5'
17
+ }
13
18
 
14
- def initialize(app)
19
+ def initialize(app, cookie_options = {})
15
20
  @app = app
21
+ @cookie = DEFAULT_COOKIE.merge(cookie_options)
16
22
  end
17
23
 
18
24
 
@@ -37,7 +43,7 @@ module Makara
37
43
  # ignore asset paths
38
44
  # consider allowing a filter proc to be provided in an initializer
39
45
  def ignore_request?(env)
40
- if defined?(Rails)
46
+ if defined?(Rails) && Rails.try(:application).try(:config).try(:assets).try(:prefix)
41
47
  if env['PATH_INFO'].to_s =~ /^#{Rails.application.config.assets.prefix}/
42
48
  return true
43
49
  end
@@ -94,16 +100,9 @@ module Makara
94
100
  # it should always be for the same path, only
95
101
  # accessible via http and live for a short amount
96
102
  # of time
97
- def store_context(status, header)
98
-
99
- cookie_value = {
100
- :path => '/',
101
- :value => "#{Makara::Context.get_current}--#{status}",
102
- :http_only => true,
103
- :max_age => '5'
104
- }
105
-
106
- Rack::Utils.set_cookie_header!(header, IDENTIFIER, cookie_value)
103
+ def store_context(status, headers)
104
+ cookie = @cookie.merge(:value => "#{Makara::Context.get_current}--#{status}")
105
+ Rack::Utils.set_cookie_header! headers, IDENTIFIER, cookie
107
106
  end
108
107
  end
109
108
  end
data/lib/makara/proxy.rb CHANGED
@@ -74,18 +74,26 @@ module Makara
74
74
 
75
75
  def stick_to_master!(write_to_cache = true)
76
76
  @master_context = Makara::Context.get_current
77
- Makara::Cache.write("makara::#{@master_context}-#{@id}", '1', @ttl) if write_to_cache
77
+ Makara::Context.stick(@master_context, @id, @ttl) if write_to_cache
78
78
  end
79
79
 
80
80
  def strategy_for(role)
81
- strategy_name = @config_parser.makara_config["#{role}_strategy".to_sym]
81
+ strategy_class_for(strategy_name_for(role)).new(self)
82
+ end
83
+
84
+ def strategy_name_for(role)
85
+ @config_parser.makara_config["#{role}_strategy".to_sym]
86
+ end
87
+
88
+ def strategy_class_for(strategy_name)
82
89
  case strategy_name
83
90
  when 'round_robin', 'roundrobin', nil, ''
84
- strategy_name = "::Makara::Strategies::RoundRobin"
91
+ ::Makara::Strategies::RoundRobin
85
92
  when 'failover'
86
- strategy_name = "::Makara::Strategies::PriorityFailover"
93
+ ::Makara::Strategies::PriorityFailover
94
+ else
95
+ strategy_name.constantize
87
96
  end
88
- strategy_name.constantize.new(self)
89
97
  end
90
98
 
91
99
  def method_missing(m, *args, &block)
@@ -198,7 +206,6 @@ module Makara
198
206
  elsif Makara::Context.get_current == @master_context
199
207
  @master_pool
200
208
 
201
- # the previous context stuck us to master
202
209
  elsif previously_stuck_to_master?
203
210
 
204
211
  # we're only on master because of the previous context so
@@ -242,8 +249,7 @@ module Makara
242
249
 
243
250
 
244
251
  def previously_stuck_to_master?
245
- return false unless @sticky
246
- !!Makara::Cache.read("makara::#{Makara::Context.get_previous}-#{@id}")
252
+ @sticky && Makara::Context.previously_stuck?(@id)
247
253
  end
248
254
 
249
255
 
@@ -3,7 +3,7 @@ module Makara
3
3
 
4
4
  MAJOR = 0
5
5
  MINOR = 3
6
- PATCH = 7
6
+ PATCH = 8
7
7
  PRE = nil
8
8
 
9
9
  def self.to_s
@@ -20,50 +20,12 @@ describe 'MakaraMysql2Adapter' do
20
20
  context "unconnected" do
21
21
 
22
22
  it 'should allow a connection to be established' do
23
- ActiveRecord::Base.establish_connection(config)
23
+ establish_connection(config)
24
24
  expect(ActiveRecord::Base.connection).to be_instance_of(ActiveRecord::ConnectionAdapters::MakaraMysql2Adapter)
25
25
  end
26
26
 
27
- it 'should not blow up if a connection fails' do
28
- wrong_config = config.deep_dup
29
- wrong_config['makara']['connections'].select{|h| h['role'] == 'slave' }.each{|h| h['username'] = 'other'}
30
-
31
- original_method = ActiveRecord::Base.method(:mysql2_connection)
32
-
33
- allow(ActiveRecord::Base).to receive(:mysql2_connection) do |config|
34
- if config[:username] == 'other'
35
- raise "could not connect"
36
- else
37
- original_method.call(config)
38
- end
39
- end
40
-
41
- ActiveRecord::Base.establish_connection(wrong_config)
42
- ActiveRecord::Base.connection
43
-
44
- load(File.dirname(__FILE__) + '/../../support/schema.rb')
45
- Makara::Context.set_current Makara::Context.generate
46
-
47
- allow(ActiveRecord::Base).to receive(:mysql2_connection) do |config|
48
- config[:username] = db_username
49
- original_method.call(config)
50
- end
51
-
52
- ActiveRecord::Base.connection.slave_pool.connections.each(&:_makara_whitelist!)
53
- ActiveRecord::Base.connection.slave_pool.provide do |con|
54
- res = con.execute('SELECT count(*) FROM users')
55
- if defined?(JRUBY_VERSION)
56
- expect(res[0]).to eq('count(*)' => 0)
57
- else
58
- expect(res.to_a[0][0]).to eq(0)
59
- end
60
- end
61
-
62
- ActiveRecord::Base.remove_connection
63
- end
64
-
65
27
  it 'should execute a send_to_all against master even if no slaves are connected' do
66
- ActiveRecord::Base.establish_connection(config)
28
+ establish_connection(config)
67
29
  connection = ActiveRecord::Base.connection
68
30
 
69
31
  connection.slave_pool.connections.each do |c|
@@ -82,7 +44,7 @@ describe 'MakaraMysql2Adapter' do
82
44
  end
83
45
 
84
46
  it 'should execute a send_to_all and raise a NoConnectionsAvailable error' do
85
- ActiveRecord::Base.establish_connection(config)
47
+ establish_connection(config)
86
48
  connection = ActiveRecord::Base.connection
87
49
 
88
50
  (connection.slave_pool.connections | connection.master_pool.connections).each do |c|
@@ -97,12 +59,56 @@ describe 'MakaraMysql2Adapter' do
97
59
 
98
60
  end
99
61
 
62
+ context "unconnect afterwards" do
63
+ after :each do
64
+ ActiveRecord::Base.clear_all_connections!
65
+ end
66
+
67
+ it 'should not blow up if a connection fails' do
68
+ wrong_config = config.deep_dup
69
+ wrong_config['makara']['connections'].select{|h| h['role'] == 'slave' }.each{|h| h['username'] = 'other'}
70
+
71
+ original_method = ActiveRecord::Base.method(:mysql2_connection)
72
+
73
+ allow(ActiveRecord::Base).to receive(:mysql2_connection) do |config|
74
+ if config[:username] == 'other'
75
+ raise "could not connect"
76
+ else
77
+ original_method.call(config)
78
+ end
79
+ end
80
+
81
+ establish_connection(wrong_config)
82
+ ActiveRecord::Base.connection
83
+
84
+ load(File.dirname(__FILE__) + '/../../support/schema.rb')
85
+ Makara::Context.set_current Makara::Context.generate
86
+
87
+ allow(ActiveRecord::Base).to receive(:mysql2_connection) do |config|
88
+ config[:username] = db_username
89
+ original_method.call(config)
90
+ end
91
+
92
+ ActiveRecord::Base.connection.slave_pool.connections.each(&:_makara_whitelist!)
93
+ ActiveRecord::Base.connection.slave_pool.provide do |con|
94
+ res = con.execute('SELECT count(*) FROM users')
95
+ if defined?(JRUBY_VERSION)
96
+ expect(res[0]).to eq('count(*)' => 0)
97
+ else
98
+ expect(res.to_a[0][0]).to eq(0)
99
+ end
100
+ end
101
+
102
+ ActiveRecord::Base.remove_connection
103
+ end
104
+ end
105
+
100
106
  end
101
107
 
102
108
  context 'with the connection established and schema loaded' do
103
109
 
104
110
  before do
105
- ActiveRecord::Base.establish_connection(config)
111
+ establish_connection(config)
106
112
  load(File.dirname(__FILE__) + '/../../support/schema.rb')
107
113
  change_context
108
114
  end
@@ -183,7 +189,7 @@ describe 'MakaraMysql2Adapter' do
183
189
  describe 'transaction support' do
184
190
  shared_examples 'a transaction supporter' do
185
191
  before do
186
- ActiveRecord::Base.establish_connection(config)
192
+ establish_connection(config)
187
193
  load(File.dirname(__FILE__) + '/../../support/schema.rb')
188
194
  change_context
189
195
 
@@ -20,15 +20,14 @@ describe 'MakaraPostgreSQLAdapter' do
20
20
 
21
21
 
22
22
  it 'should allow a connection to be established' do
23
- ActiveRecord::Base.establish_connection(config)
23
+ establish_connection(config)
24
24
  expect(ActiveRecord::Base.connection).to be_instance_of(ActiveRecord::ConnectionAdapters::MakaraPostgreSQLAdapter)
25
25
  end
26
26
 
27
27
  context 'with the connection established and schema loaded' do
28
28
 
29
29
  before do
30
- puts config
31
- ActiveRecord::Base.establish_connection(config)
30
+ establish_connection(config)
32
31
  load(File.dirname(__FILE__) + '/../../support/schema.rb')
33
32
  change_context
34
33
  end
@@ -95,7 +94,7 @@ describe 'MakaraPostgreSQLAdapter' do
95
94
  custom_config = config.deep_dup
96
95
  custom_config['makara']['connections'].select{|h| h['role'] == 'slave' }.each{|h| h['port'] = '1'}
97
96
 
98
- ActiveRecord::Base.establish_connection(custom_config)
97
+ establish_connection(custom_config)
99
98
  load(File.dirname(__FILE__) + '/../../support/schema.rb')
100
99
 
101
100
  connection.execute('SELECT * FROM users')
@@ -105,14 +104,14 @@ describe 'MakaraPostgreSQLAdapter' do
105
104
 
106
105
  context 'with only slave connection' do
107
106
  it 'should raise error only on write' do
108
- ActiveRecord::Base.establish_connection(config)
107
+ establish_connection(config)
109
108
  load(File.dirname(__FILE__) + '/../../support/schema.rb')
110
109
  ActiveRecord::Base.clear_all_connections!
111
110
 
112
111
  custom_config = config.deep_dup
113
112
  custom_config['makara']['connections'].select{|h| h['role'] == 'master' }.each{|h| h['port'] = '1'}
114
113
 
115
- ActiveRecord::Base.establish_connection(custom_config)
114
+ establish_connection(custom_config)
116
115
 
117
116
  connection.execute('SELECT * FROM users')
118
117
  expect { connection.execute('INSERT INTO users (name) VALUES (\'John\')') }.to raise_error(Makara::Errors::NoConnectionsAvailable)
@@ -122,7 +121,7 @@ describe 'MakaraPostgreSQLAdapter' do
122
121
  describe 'transaction support' do
123
122
  shared_examples 'a transaction supporter' do
124
123
  before do
125
- ActiveRecord::Base.establish_connection(config)
124
+ establish_connection(config)
126
125
  load(File.dirname(__FILE__) + '/../../support/schema.rb')
127
126
  change_context
128
127
 
@@ -22,12 +22,19 @@ describe Makara::ConnectionWrapper do
22
22
  expect(subject._makara_weight).to eq(1)
23
23
  end
24
24
 
25
- it 'should store the blacklist status' do
26
- expect(subject._makara_blacklisted?).to eq(false)
27
- subject._makara_blacklist!
28
- expect(subject._makara_blacklisted?).to eq(true)
29
- subject._makara_whitelist!
30
- expect(subject._makara_blacklisted?).to eq(false)
25
+ context '#_makara_blacklisted?' do
26
+ it 'should store the blacklist status' do
27
+ expect(subject._makara_blacklisted?).to eq(false)
28
+ subject._makara_blacklist!
29
+ expect(subject._makara_blacklisted?).to eq(true)
30
+ subject._makara_whitelist!
31
+ expect(subject._makara_blacklisted?).to eq(false)
32
+ end
33
+
34
+ it 'should handle frozen pre-epoch dates' do
35
+ Timecop.freeze(Date.new(1900)) do
36
+ expect(subject._makara_blacklisted?).to eq(false)
37
+ end
38
+ end
31
39
  end
32
-
33
40
  end
data/spec/context_spec.rb CHANGED
@@ -101,7 +101,46 @@ describe Makara::Context do
101
101
  threads.map(&:join)
102
102
  expect(uniq_curret_contexts.uniq.count).to eq(3)
103
103
  end
104
+
105
+ it 'clears config sticky cache' do
106
+ Makara::Cache.store = :memory
107
+
108
+ Makara::Context.set_previous('a')
109
+ Makara::Context.stick('a', 1, 10)
110
+ expect(Makara::Context.previously_stuck?(1)).to be_truthy
111
+
112
+ Makara::Context.set_previous('b')
113
+ expect(Makara::Context.previously_stuck?(1)).to be_falsey
114
+ end
115
+ end
116
+
117
+ describe 'stick' do
118
+ it 'sticks a config to master for subsequent requests' do
119
+ Makara::Cache.store = :memory
120
+
121
+ expect(Makara::Context.stuck?('context', 1)).to be_falsey
122
+
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
126
+ end
104
127
  end
105
128
 
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'
133
+
134
+ # Emulate sticking the previous web request to master.
135
+ Makara::Context.stick 'previous', 1, 10
136
+
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
140
+
141
+ # Other configs should not be stuck to master, though.
142
+ expect(Makara::Context.previously_stuck?(2)).to be_falsey
143
+ end
144
+ end
106
145
  end
107
146
 
@@ -11,7 +11,7 @@ describe Makara::Middleware do
11
11
 
12
12
  let(:env){ {} }
13
13
  let(:proxy){ FakeProxy.new(config(1,2)) }
14
- let(:middleware){ described_class.new(app) }
14
+ let(:middleware){ described_class.new(app, :secure => true) }
15
15
 
16
16
  let(:key){ Makara::Middleware::IDENTIFIER }
17
17
 
@@ -56,7 +56,7 @@ describe Makara::Middleware do
56
56
 
57
57
  status, headers, body = middleware.call(env)
58
58
 
59
- expect(headers['Set-Cookie']).to eq("#{key}=#{Makara::Context.get_current}--200; path=/; max-age=5; HttpOnly")
59
+ expect(headers['Set-Cookie']).to eq("#{key}=#{Makara::Context.get_current}--200; path=/; max-age=5; secure; HttpOnly")
60
60
  end
61
61
 
62
62
  it 'should preserve the same context if the previous request was a redirect' do
data/spec/spec_helper.rb CHANGED
@@ -19,13 +19,13 @@ RSpec.configure do |config|
19
19
 
20
20
  config.order = 'random'
21
21
 
22
+ require "#{File.dirname(__FILE__)}/support/helpers"
22
23
  require "#{File.dirname(__FILE__)}/support/proxy_extensions"
23
24
  require "#{File.dirname(__FILE__)}/support/pool_extensions"
24
- require "#{File.dirname(__FILE__)}/support/configurator"
25
25
  require "#{File.dirname(__FILE__)}/support/mock_objects"
26
26
  require "#{File.dirname(__FILE__)}/support/deep_dup"
27
27
 
28
- config.include Configurator
28
+ config.include SpecHelpers
29
29
 
30
30
  config.before :each do
31
31
  Makara::Cache.store = :memory
@@ -0,0 +1,23 @@
1
+ module SpecHelpers
2
+ def establish_connection(config)
3
+ connection = ActiveRecord::Base.establish_connection(config)
4
+
5
+ # make sure these are all reset to not be blacklisted
6
+ ActiveRecord::Base.connection.slave_pool.connections.each(&:_makara_whitelist!)
7
+ ActiveRecord::Base.connection.master_pool.connections.each(&:_makara_whitelist!)
8
+
9
+ ActiveRecord::Base.connection
10
+ end
11
+
12
+ def config(masters = 1, slaves = 2)
13
+ connections = []
14
+ masters.times{ connections << {:role => 'master'} }
15
+ slaves.times{ connections << {:role => 'slave'} }
16
+ {
17
+ :makara => {
18
+ :blacklist_duration => 30,
19
+ :connections => connections
20
+ }
21
+ }
22
+ end
23
+ end
@@ -1,6 +1,8 @@
1
1
  ActiveRecord::Schema.define(:version => 20130628161227) do
2
2
 
3
- create_table "users", :force => true do |t|
3
+ drop_table "users" if table_exists? "users"
4
+
5
+ create_table "users" do |t|
4
6
  t.string "name"
5
7
  end
6
8
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: makara
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.7
4
+ version: 0.3.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Nelson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-22 00:00:00.000000000 Z
11
+ date: 2017-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -34,19 +34,21 @@ files:
34
34
  - ".gitignore"
35
35
  - ".rspec"
36
36
  - ".ruby-gemset"
37
- - ".ruby-version"
38
37
  - ".travis.yml"
39
38
  - CHANGELOG.md
40
39
  - Gemfile
41
40
  - LICENSE.txt
42
41
  - README.md
43
42
  - Rakefile
43
+ - gemfiles/ar-head.gemfile
44
44
  - gemfiles/ar30.gemfile
45
45
  - gemfiles/ar31.gemfile
46
46
  - gemfiles/ar32.gemfile
47
47
  - gemfiles/ar40.gemfile
48
48
  - gemfiles/ar41.gemfile
49
49
  - gemfiles/ar42.gemfile
50
+ - gemfiles/ar50.gemfile
51
+ - gemfiles/ar51.gemfile
50
52
  - lib/active_record/connection_adapters/jdbcmysql_makara_adapter.rb
51
53
  - lib/active_record/connection_adapters/jdbcpostgresql_makara_adapter.rb
52
54
  - lib/active_record/connection_adapters/makara_abstract_adapter.rb
@@ -66,6 +68,7 @@ files:
66
68
  - lib/makara/error_handler.rb
67
69
  - lib/makara/errors/all_connections_blacklisted.rb
68
70
  - lib/makara/errors/blacklist_connection.rb
71
+ - lib/makara/errors/makara_error.rb
69
72
  - lib/makara/errors/no_connections_available.rb
70
73
  - lib/makara/logging/logger.rb
71
74
  - lib/makara/logging/subscriber.rb
@@ -92,8 +95,8 @@ files:
92
95
  - spec/spec_helper.rb
93
96
  - spec/strategies/priority_failover_spec.rb
94
97
  - spec/strategies/round_robin_spec.rb
95
- - spec/support/configurator.rb
96
98
  - spec/support/deep_dup.rb
99
+ - spec/support/helpers.rb
97
100
  - spec/support/mock_objects.rb
98
101
  - spec/support/mysql2_database.yml
99
102
  - spec/support/mysql2_database_with_custom_errors.yml
@@ -120,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
123
  version: '0'
121
124
  requirements: []
122
125
  rubyforge_project:
123
- rubygems_version: 2.6.1
126
+ rubygems_version: 2.5.2
124
127
  signing_key:
125
128
  specification_version: 4
126
129
  summary: Read-write split your DB yo
@@ -139,8 +142,8 @@ test_files:
139
142
  - spec/spec_helper.rb
140
143
  - spec/strategies/priority_failover_spec.rb
141
144
  - spec/strategies/round_robin_spec.rb
142
- - spec/support/configurator.rb
143
145
  - spec/support/deep_dup.rb
146
+ - spec/support/helpers.rb
144
147
  - spec/support/mock_objects.rb
145
148
  - spec/support/mysql2_database.yml
146
149
  - spec/support/mysql2_database_with_custom_errors.yml
@@ -148,4 +151,3 @@ test_files:
148
151
  - spec/support/postgresql_database.yml
149
152
  - spec/support/proxy_extensions.rb
150
153
  - spec/support/schema.rb
151
- has_rdoc:
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 2.1.5
@@ -1,13 +0,0 @@
1
- module Configurator
2
- def config(masters = 1, slaves = 2)
3
- connections = []
4
- masters.times{ connections << {:role => 'master'} }
5
- slaves.times{ connections << {:role => 'slave'} }
6
- {
7
- :makara => {
8
- :blacklist_duration => 30,
9
- :connections => connections
10
- }
11
- }
12
- end
13
- end