makara 0.3.7 → 0.3.8

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