guardrail 2.0.1 → 3.0.0
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 +4 -4
- data/README.md +9 -37
- data/lib/guard_rail.rb +8 -103
- data/lib/guard_rail/version.rb +1 -1
- metadata +11 -58
- data/lib/guard_rail/connection_handler.rb +0 -15
- data/lib/guard_rail/connection_specification.rb +0 -79
- data/lib/guard_rail/railtie.rb +0 -11
- data/spec/guard_rail_spec.rb +0 -169
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b9e58f5329f5eda67ce7018576fc6c2d970df8325c3f60646caf25c2a185fc9
|
4
|
+
data.tar.gz: 5450d44f587e98fe84d12a5572f7aa2cde259fc75aebc9d1f28f4c535510af16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1c38cf3c156354856914ebba409fb4e5cb1287109ad66e07da1b0bd831e4dd522487bec8ba1b8bd056fafac7710747ffe691dbdf59a29b14f03999938ec687a
|
7
|
+
data.tar.gz: 5a8e7b29e2006a618045c1d17950b17bbaa13fa479589fc93b061055ea6f4ba80a6ccdfa532e75bb9cadc4cdaebd36a2c5b07261d7223b5f235491871e5913bf
|
data/README.md
CHANGED
@@ -3,55 +3,27 @@ GuardRail
|
|
3
3
|
|
4
4
|
## About
|
5
5
|
|
6
|
-
GuardRail
|
7
|
-
ActiveRecord, allowing least-privilege best practices.
|
6
|
+
GuardRail is a thin wrapper around Rail 6.1's native role switching.
|
8
7
|
|
9
8
|
## Installation
|
10
9
|
|
11
|
-
Add `gem 'guardrail'` to your Gemfile
|
12
|
-
with the release candidate for Rails 6.0)
|
10
|
+
Add `gem 'guardrail'` to your Gemfile.
|
13
11
|
|
14
12
|
## Usage
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
database.yml, then wrapping stuff you want to query the replica in GuardRail.activate(:replica) blocks.
|
19
|
-
You can extend this to a deploy environment so that migrations will run as a deploy user that
|
20
|
-
permission to modify schema, while your normal app runs with lower privileges that cannot modify
|
21
|
-
schema. This is defense-in-depth in practice, so that *if* you happen to have a SQL injection
|
22
|
-
bug, it would be impossible to do something like dropping tables.
|
14
|
+
See https://guides.rubyonrails.org/active_record_multiple_databases.html. GuardRail simply adds
|
15
|
+
syntactic sugar to easily switch to different roles:
|
23
16
|
|
24
|
-
The other major use case is more defense-in-depth. By carefully setting up your environment, you
|
25
|
-
can default to script/console sessions for regular users to use their own database user, and the
|
26
|
-
replica.
|
27
|
-
|
28
|
-
Example database.yml file:
|
29
|
-
|
30
|
-
```yaml
|
31
|
-
production:
|
32
|
-
adapter: postgresql
|
33
|
-
username: myapp
|
34
|
-
database: myapp
|
35
|
-
host: db-primary
|
36
|
-
replica:
|
37
|
-
host: db-replica
|
38
|
-
deploy:
|
39
|
-
username: deploy
|
40
|
-
```
|
41
|
-
|
42
|
-
Using an initializer, you can achieve the default environment settings (in tandem with profile
|
43
|
-
changes):
|
44
17
|
|
45
18
|
```ruby
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
GuardRail.apply_config!(:username => ENV['RAILS_DATABASE_USER'])
|
19
|
+
def some_method
|
20
|
+
GuardRails.activate(:secondary) do
|
21
|
+
MyModel.some_really_long_query
|
22
|
+
end
|
51
23
|
end
|
52
24
|
```
|
53
25
|
|
54
|
-
Additionally
|
26
|
+
Additionally you can include GuardRail::HelperMethods and use several helpers
|
55
27
|
to execute methods on specific environments:
|
56
28
|
|
57
29
|
```ruby
|
data/lib/guard_rail.rb
CHANGED
@@ -1,114 +1,19 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module GuardRail
|
4
4
|
class << self
|
5
|
-
attr_accessor :primary_environment_name
|
6
|
-
GuardRail.primary_environment_name = :primary
|
7
|
-
|
8
5
|
def environment
|
9
|
-
|
10
|
-
end
|
11
|
-
|
12
|
-
def global_config
|
13
|
-
@global_config ||= {}
|
14
|
-
end
|
15
|
-
|
16
|
-
def activated_environments
|
17
|
-
@activated_environments ||= Set.new()
|
18
|
-
end
|
19
|
-
|
20
|
-
# semi-private
|
21
|
-
def initialize!
|
22
|
-
require 'guard_rail/connection_handler'
|
23
|
-
require 'guard_rail/connection_specification'
|
24
|
-
require 'guard_rail/helper_methods'
|
25
|
-
|
26
|
-
activated_environments << GuardRail.environment
|
27
|
-
|
28
|
-
ActiveRecord::ConnectionAdapters::ConnectionHandler.prepend(ConnectionHandler)
|
29
|
-
ActiveRecord::ConnectionAdapters::ConnectionSpecification.prepend(ConnectionSpecification)
|
30
|
-
end
|
31
|
-
|
32
|
-
def global_config_sequence
|
33
|
-
@global_config_sequence ||= 1
|
34
|
-
end
|
35
|
-
|
36
|
-
def bump_sequence
|
37
|
-
@global_config_sequence ||= 1
|
38
|
-
@global_config_sequence += 1
|
39
|
-
ActiveRecord::Base::connection_handler.clear_all_connections!
|
40
|
-
end
|
41
|
-
|
42
|
-
# for altering other pieces of config (i.e. username)
|
43
|
-
# will force a disconnect
|
44
|
-
def apply_config!(hash)
|
45
|
-
global_config.merge!(hash)
|
46
|
-
bump_sequence
|
47
|
-
end
|
48
|
-
|
49
|
-
def remove_config!(key)
|
50
|
-
global_config.delete(key)
|
51
|
-
bump_sequence
|
52
|
-
end
|
53
|
-
|
54
|
-
def connection_handlers
|
55
|
-
save_handler
|
56
|
-
@connection_handlers
|
57
|
-
end
|
58
|
-
|
59
|
-
# switch environment for the duration of the block
|
60
|
-
# will keep the old connections around
|
61
|
-
def activate(environment)
|
62
|
-
environment ||= primary_environment_name
|
63
|
-
return yield if environment == self.environment
|
64
|
-
begin
|
65
|
-
old_environment = activate!(environment)
|
66
|
-
activated_environments << environment
|
67
|
-
yield
|
68
|
-
ensure
|
69
|
-
Thread.current[:guard_rail_environment] = old_environment
|
70
|
-
ActiveRecord::Base.connection_handler = ensure_handler unless test?
|
71
|
-
end
|
6
|
+
ActiveRecord::Base.current_role
|
72
7
|
end
|
73
8
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
save_handler
|
78
|
-
old_environment = self.environment
|
79
|
-
Thread.current[:guard_rail_environment] = environment
|
80
|
-
ActiveRecord::Base.connection_handler = ensure_handler unless test?
|
81
|
-
old_environment
|
9
|
+
def activate(role)
|
10
|
+
return yield if environment == role
|
11
|
+
ActiveRecord::Base.connected_to(role: role) { yield }
|
82
12
|
end
|
83
13
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
Rails.env.test?
|
88
|
-
end
|
89
|
-
|
90
|
-
def save_handler
|
91
|
-
@connection_handlers ||= {}
|
92
|
-
@connection_handlers[environment] ||= ActiveRecord::Base.connection_handler
|
93
|
-
end
|
94
|
-
|
95
|
-
def ensure_handler
|
96
|
-
new_handler = @connection_handlers[environment]
|
97
|
-
if !new_handler
|
98
|
-
new_handler = @connection_handlers[environment] = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
|
99
|
-
pools = ActiveRecord::Base.connection_handler.send(:owner_to_pool)
|
100
|
-
pools.each_pair do |model, pool|
|
101
|
-
new_handler.establish_connection(pool.spec.config)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
new_handler
|
14
|
+
def activate!(role)
|
15
|
+
return if environment == role
|
16
|
+
ActiveRecord::Base.connecting_to(role: role)
|
105
17
|
end
|
106
18
|
end
|
107
19
|
end
|
108
|
-
|
109
|
-
if defined?(Rails::Railtie)
|
110
|
-
require "guard_rail/railtie"
|
111
|
-
else
|
112
|
-
# just load everything immediately for Rails 2
|
113
|
-
GuardRail.initialize!
|
114
|
-
end
|
data/lib/guard_rail/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: guardrail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cody Cutrer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,40 +16,40 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '6.1'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '6.
|
22
|
+
version: '6.2'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
29
|
+
version: '6.1'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '6.
|
32
|
+
version: '6.2'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: railties
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '
|
39
|
+
version: '6.1'
|
40
40
|
- - "<"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: '6.
|
42
|
+
version: '6.2'
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
47
|
- - ">="
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version: '
|
49
|
+
version: '6.1'
|
50
50
|
- - "<"
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: '6.
|
52
|
+
version: '6.2'
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: appraisal
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,48 +78,6 @@ dependencies:
|
|
78
78
|
- - ">="
|
79
79
|
- !ruby/object:Gem::Version
|
80
80
|
version: '0'
|
81
|
-
- !ruby/object:Gem::Dependency
|
82
|
-
name: mocha
|
83
|
-
requirement: !ruby/object:Gem::Requirement
|
84
|
-
requirements:
|
85
|
-
- - ">="
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
version: '0'
|
88
|
-
type: :development
|
89
|
-
prerelease: false
|
90
|
-
version_requirements: !ruby/object:Gem::Requirement
|
91
|
-
requirements:
|
92
|
-
- - ">="
|
93
|
-
- !ruby/object:Gem::Version
|
94
|
-
version: '0'
|
95
|
-
- !ruby/object:Gem::Dependency
|
96
|
-
name: rspec
|
97
|
-
requirement: !ruby/object:Gem::Requirement
|
98
|
-
requirements:
|
99
|
-
- - "~>"
|
100
|
-
- !ruby/object:Gem::Version
|
101
|
-
version: '3.0'
|
102
|
-
type: :development
|
103
|
-
prerelease: false
|
104
|
-
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
requirements:
|
106
|
-
- - "~>"
|
107
|
-
- !ruby/object:Gem::Version
|
108
|
-
version: '3.0'
|
109
|
-
- !ruby/object:Gem::Dependency
|
110
|
-
name: sqlite3
|
111
|
-
requirement: !ruby/object:Gem::Requirement
|
112
|
-
requirements:
|
113
|
-
- - ">="
|
114
|
-
- !ruby/object:Gem::Version
|
115
|
-
version: '0'
|
116
|
-
type: :development
|
117
|
-
prerelease: false
|
118
|
-
version_requirements: !ruby/object:Gem::Requirement
|
119
|
-
requirements:
|
120
|
-
- - ">="
|
121
|
-
- !ruby/object:Gem::Version
|
122
|
-
version: '0'
|
123
81
|
description: Allows multiple environments in database.yml, and dynamically switching
|
124
82
|
them.
|
125
83
|
email: cody@instructure.com
|
@@ -130,13 +88,9 @@ files:
|
|
130
88
|
- LICENSE
|
131
89
|
- README.md
|
132
90
|
- lib/guard_rail.rb
|
133
|
-
- lib/guard_rail/connection_handler.rb
|
134
|
-
- lib/guard_rail/connection_specification.rb
|
135
91
|
- lib/guard_rail/helper_methods.rb
|
136
|
-
- lib/guard_rail/railtie.rb
|
137
92
|
- lib/guard_rail/version.rb
|
138
93
|
- lib/guardrail.rb
|
139
|
-
- spec/guard_rail_spec.rb
|
140
94
|
homepage: http://github.com/instructure/guardrail
|
141
95
|
licenses:
|
142
96
|
- MIT
|
@@ -160,5 +114,4 @@ rubygems_version: 3.1.4
|
|
160
114
|
signing_key:
|
161
115
|
specification_version: 4
|
162
116
|
summary: ActiveRecord database environment switching for secondaries and least-privilege
|
163
|
-
test_files:
|
164
|
-
- spec/guard_rail_spec.rb
|
117
|
+
test_files: []
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module GuardRail
|
4
|
-
module ConnectionHandler
|
5
|
-
%w{clear_active_connections clear_reloadable_connections
|
6
|
-
clear_all_connections verify_active_connections }.each do |method|
|
7
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
8
|
-
def #{method}!(super_method: false)
|
9
|
-
return super() if super_method
|
10
|
-
::GuardRail.connection_handlers.values.each { |handler| handler.#{method}!(super_method: true) }
|
11
|
-
end
|
12
|
-
RUBY
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,79 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'i18n/core_ext/hash' unless Hash.method_defined?(:deep_symbolize_keys)
|
4
|
-
|
5
|
-
module GuardRail
|
6
|
-
module ConnectionSpecification
|
7
|
-
class CacheCoherentHash < Hash
|
8
|
-
def initialize(spec)
|
9
|
-
@spec = spec
|
10
|
-
super
|
11
|
-
end
|
12
|
-
|
13
|
-
def []=(key, value)
|
14
|
-
super
|
15
|
-
@spec.instance_variable_set(:@current_config, nil)
|
16
|
-
@spec.instance_variable_get(:@config)[key] = value
|
17
|
-
end
|
18
|
-
|
19
|
-
def delete(key)
|
20
|
-
super
|
21
|
-
@spec.instance_variable_set(:@current_config, nil)
|
22
|
-
@spec.instance_variable_get(:@config).delete(key)
|
23
|
-
end
|
24
|
-
|
25
|
-
def dup
|
26
|
-
Hash[self]
|
27
|
-
end
|
28
|
-
|
29
|
-
# in rails 4.2, active support tries to create a copy of the original object's class
|
30
|
-
# instead of making a new Hash object, so it fails since initialize expects an argument
|
31
|
-
def transform_keys(&block)
|
32
|
-
dup.transform_keys(&block)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def initialize(name, config, adapter_method)
|
37
|
-
super(name, config.deep_symbolize_keys, adapter_method)
|
38
|
-
end
|
39
|
-
|
40
|
-
def initialize_dup(original)
|
41
|
-
@current_config = nil
|
42
|
-
super
|
43
|
-
end
|
44
|
-
|
45
|
-
def config
|
46
|
-
@current_config = nil if GuardRail.environment != @current_config_environment || GuardRail.global_config_sequence != @current_config_sequence
|
47
|
-
return @current_config if @current_config
|
48
|
-
|
49
|
-
@current_config_environment = GuardRail.environment
|
50
|
-
@current_config_sequence = GuardRail.global_config_sequence
|
51
|
-
config = @config.dup
|
52
|
-
if @config.has_key?(GuardRail.environment)
|
53
|
-
env_config = @config[GuardRail.environment]
|
54
|
-
# an array of databases for this environment; for now, just choose the first non-nil element
|
55
|
-
if env_config.is_a?(Array)
|
56
|
-
env_config = env_config.detect { |individual_config| !individual_config.nil? }
|
57
|
-
end
|
58
|
-
config.merge!(env_config.symbolize_keys)
|
59
|
-
end
|
60
|
-
|
61
|
-
config.keys.each do |key|
|
62
|
-
next unless config[key].is_a?(String)
|
63
|
-
config[key] = config[key] % config
|
64
|
-
end
|
65
|
-
|
66
|
-
config.merge!(GuardRail.global_config)
|
67
|
-
|
68
|
-
@current_config = CacheCoherentHash.new(self)
|
69
|
-
@current_config.replace(config)
|
70
|
-
|
71
|
-
@current_config
|
72
|
-
end
|
73
|
-
|
74
|
-
def config=(value)
|
75
|
-
@config = value
|
76
|
-
@current_config = nil
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
data/lib/guard_rail/railtie.rb
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module GuardRail
|
4
|
-
class Railtie < Rails::Railtie
|
5
|
-
initializer "guard_rail.extend_ar", :before => "active_record.initialize_database" do
|
6
|
-
ActiveSupport.on_load(:active_record) do
|
7
|
-
GuardRail.initialize!
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
data/spec/guard_rail_spec.rb
DELETED
@@ -1,169 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_record'
|
4
|
-
require 'byebug'
|
5
|
-
require 'rails'
|
6
|
-
require 'guard_rail'
|
7
|
-
|
8
|
-
# we're not actually bringing up ActiveRecord, so we need to initialize our stuff
|
9
|
-
GuardRail.initialize!
|
10
|
-
|
11
|
-
RSpec.configure do |config|
|
12
|
-
config.mock_framework = :mocha
|
13
|
-
end
|
14
|
-
|
15
|
-
describe GuardRail do
|
16
|
-
ConnectionSpecification = ActiveRecord::ConnectionAdapters::ConnectionSpecification
|
17
|
-
|
18
|
-
def spec_args(conf, adapter)
|
19
|
-
['dummy', conf, adapter]
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should allow changing environments" do
|
23
|
-
conf = {
|
24
|
-
:adapter => 'postgresql',
|
25
|
-
:database => 'primary',
|
26
|
-
:username => 'canvas',
|
27
|
-
:deploy => {
|
28
|
-
:username => 'deploy'
|
29
|
-
},
|
30
|
-
:replica => {
|
31
|
-
:database => 'replica'
|
32
|
-
}
|
33
|
-
}
|
34
|
-
spec = ConnectionSpecification.new(*spec_args(conf, 'adapter'))
|
35
|
-
expect(spec.config[:username]).to eq('canvas')
|
36
|
-
expect(spec.config[:database]).to eq('primary')
|
37
|
-
GuardRail.activate(:deploy) do
|
38
|
-
expect(spec.config[:username]).to eq('deploy')
|
39
|
-
expect(spec.config[:database]).to eq('primary')
|
40
|
-
end
|
41
|
-
expect(spec.config[:username]).to eq('canvas')
|
42
|
-
expect(spec.config[:database]).to eq('primary')
|
43
|
-
GuardRail.activate(:replica) do
|
44
|
-
expect(spec.config[:username]).to eq('canvas')
|
45
|
-
expect(spec.config[:database]).to eq('replica')
|
46
|
-
end
|
47
|
-
expect(spec.config[:username]).to eq('canvas')
|
48
|
-
expect(spec.config[:database]).to eq('primary')
|
49
|
-
end
|
50
|
-
|
51
|
-
it "should allow using hash insertions" do
|
52
|
-
conf = {
|
53
|
-
:adapter => 'postgresql',
|
54
|
-
:database => 'primary',
|
55
|
-
:username => '%{schema_search_path}',
|
56
|
-
:schema_search_path => 'canvas',
|
57
|
-
:deploy => {
|
58
|
-
:username => 'deploy'
|
59
|
-
}
|
60
|
-
}
|
61
|
-
spec = ConnectionSpecification.new(*spec_args(conf, 'adapter'))
|
62
|
-
expect(spec.config[:username]).to eq('canvas')
|
63
|
-
GuardRail.activate(:deploy) do
|
64
|
-
expect(spec.config[:username]).to eq('deploy')
|
65
|
-
end
|
66
|
-
expect(spec.config[:username]).to eq('canvas')
|
67
|
-
end
|
68
|
-
|
69
|
-
it "should be cache coherent with modifying the config" do
|
70
|
-
conf = {
|
71
|
-
:adapter => 'postgresql',
|
72
|
-
:database => 'primary',
|
73
|
-
:username => '%{schema_search_path}',
|
74
|
-
:schema_search_path => 'canvas',
|
75
|
-
:deploy => {
|
76
|
-
:username => 'deploy'
|
77
|
-
}
|
78
|
-
}
|
79
|
-
spec = ConnectionSpecification.new(*spec_args(conf.dup, 'adapter'))
|
80
|
-
expect(spec.config[:username]).to eq('canvas')
|
81
|
-
spec.config[:schema_search_path] = 'bob'
|
82
|
-
expect(spec.config[:schema_search_path]).to eq('bob')
|
83
|
-
expect(spec.config[:username]).to eq('bob')
|
84
|
-
GuardRail.activate(:deploy) do
|
85
|
-
expect(spec.config[:schema_search_path]).to eq('bob')
|
86
|
-
expect(spec.config[:username]).to eq('deploy')
|
87
|
-
end
|
88
|
-
external_config = spec.config.dup
|
89
|
-
expect(external_config.class).to eq(Hash)
|
90
|
-
expect(external_config).to eq(spec.config)
|
91
|
-
|
92
|
-
spec.config = conf.dup
|
93
|
-
expect(spec.config[:username]).to eq('canvas')
|
94
|
-
end
|
95
|
-
|
96
|
-
it "does not share config objects when dup'ing specs" do
|
97
|
-
conf = {
|
98
|
-
:adapter => 'postgresql',
|
99
|
-
:database => 'primary',
|
100
|
-
:username => '%{schema_search_path}',
|
101
|
-
:schema_search_path => 'canvas',
|
102
|
-
:deploy => {
|
103
|
-
:username => 'deploy'
|
104
|
-
}
|
105
|
-
}
|
106
|
-
spec = ConnectionSpecification.new(*spec_args(conf.dup, 'adapter'))
|
107
|
-
expect(spec.config.object_id).not_to eq spec.dup.config.object_id
|
108
|
-
end
|
109
|
-
|
110
|
-
describe "activate" do
|
111
|
-
before do
|
112
|
-
#!!! trick it in to actually switching envs
|
113
|
-
Rails.env.stubs(:test?).returns(false)
|
114
|
-
|
115
|
-
# be sure to test bugs where the current env isn't yet included in this hash
|
116
|
-
GuardRail.connection_handlers.clear
|
117
|
-
|
118
|
-
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
|
119
|
-
end
|
120
|
-
|
121
|
-
it "should call ensure_handler when switching envs" do
|
122
|
-
old_handler = ActiveRecord::Base.connection_handler
|
123
|
-
GuardRail.expects(:ensure_handler).returns(old_handler).twice
|
124
|
-
GuardRail.activate(:replica) {}
|
125
|
-
end
|
126
|
-
|
127
|
-
it "should not close connections when switching envs" do
|
128
|
-
conn = ActiveRecord::Base.connection
|
129
|
-
replica_conn = GuardRail.activate(:replica) { ActiveRecord::Base.connection }
|
130
|
-
expect(conn).not_to eq(replica_conn)
|
131
|
-
expect(ActiveRecord::Base.connection).to eq(conn)
|
132
|
-
end
|
133
|
-
|
134
|
-
it "should track all activated environments" do
|
135
|
-
GuardRail.activate(:replica) {}
|
136
|
-
GuardRail.activate(:custom) {}
|
137
|
-
expected = Set.new([:primary, :replica, :custom])
|
138
|
-
expect(GuardRail.activated_environments & expected).to eq(expected)
|
139
|
-
end
|
140
|
-
|
141
|
-
context "non-transactional" do
|
142
|
-
it "should really disconnect all envs" do
|
143
|
-
ActiveRecord::Base.connection
|
144
|
-
expect(ActiveRecord::Base.connection_pool).to be_connected
|
145
|
-
|
146
|
-
GuardRail.activate(:replica) do
|
147
|
-
ActiveRecord::Base.connection
|
148
|
-
expect(ActiveRecord::Base.connection_pool).to be_connected
|
149
|
-
end
|
150
|
-
|
151
|
-
ActiveRecord::Base.clear_all_connections!
|
152
|
-
expect(ActiveRecord::Base.connection_pool).not_to be_connected
|
153
|
-
GuardRail.activate(:replica) do
|
154
|
-
expect(ActiveRecord::Base.connection_pool).not_to be_connected
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
it 'is thread safe' do
|
160
|
-
GuardRail.activate(:replica) do
|
161
|
-
Thread.new do
|
162
|
-
GuardRail.activate!(:deploy)
|
163
|
-
expect(GuardRail.environment).to eq :deploy
|
164
|
-
end.join
|
165
|
-
expect(GuardRail.environment).to eq :replica
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|