innkeeper 0.1.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 +7 -0
- data/.gitignore +15 -0
- data/.pryrc +3 -0
- data/.travis.yml +15 -0
- data/Appraisals +20 -0
- data/Gemfile +10 -0
- data/Guardfile +24 -0
- data/HISTORY.md +337 -0
- data/README.md +485 -0
- data/Rakefile +92 -0
- data/TODO.md +51 -0
- data/gemfiles/rails_5_1.gemfile +12 -0
- data/innkeeper.gemspec +42 -0
- data/lib/generators/innkeeper/install/USAGE +5 -0
- data/lib/generators/innkeeper/install/install_generator.rb +10 -0
- data/lib/generators/innkeeper/install/templates/innkeeper.rb +76 -0
- data/lib/innkeeper.rb +110 -0
- data/lib/innkeeper/adapters/abstract_adapter.rb +172 -0
- data/lib/innkeeper/adapters/mysql2_adapter.rb +47 -0
- data/lib/innkeeper/adapters/postgresql_adapter.rb +112 -0
- data/lib/innkeeper/console.rb +12 -0
- data/lib/innkeeper/deprecation.rb +10 -0
- data/lib/innkeeper/elevators/domain.rb +20 -0
- data/lib/innkeeper/elevators/generic.rb +32 -0
- data/lib/innkeeper/elevators/host_hash.rb +22 -0
- data/lib/innkeeper/elevators/subdomain.rb +62 -0
- data/lib/innkeeper/migrator.rb +33 -0
- data/lib/innkeeper/railtie.rb +56 -0
- data/lib/innkeeper/resolvers/abstract.rb +15 -0
- data/lib/innkeeper/resolvers/database.rb +11 -0
- data/lib/innkeeper/resolvers/schema.rb +14 -0
- data/lib/innkeeper/tasks/enhancements.rb +36 -0
- data/lib/innkeeper/tenant.rb +47 -0
- data/lib/innkeeper/version.rb +3 -0
- data/lib/tasks/innkeeper.rake +128 -0
- data/notes.md +31 -0
- data/test/config_test.rb +52 -0
- data/test/databases.yml.sample +37 -0
- data/test/decorator_test.rb +21 -0
- data/test/domain_elevator_test.rb +38 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/controllers/application_controller.rb +6 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/company.rb +3 -0
- data/test/dummy/app/models/user.rb +3 -0
- data/test/dummy/app/views/application/index.html.erb +1 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +49 -0
- data/test/dummy/config/boot.rb +11 -0
- data/test/dummy/config/database.yml.sample +38 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +27 -0
- data/test/dummy/config/environments/production.rb +51 -0
- data/test/dummy/config/environments/test.rb +34 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/innkeeper.rb +4 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/db/schema.rb +19 -0
- data/test/dummy/db/seeds.rb +5 -0
- data/test/dummy/db/seeds/import.rb +5 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/stylesheets/.gitkeep +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/excluded_models_test.rb +32 -0
- data/test/generic_elevator_test.rb +63 -0
- data/test/host_hash_elevator_test.rb +42 -0
- data/test/innkeeper_test.rb +96 -0
- data/test/mocks/adapter_mock.rb +11 -0
- data/test/multithreading_test.rb +37 -0
- data/test/mysql2_adapter_test.rb +17 -0
- data/test/postgresql_adapter_test.rb +39 -0
- data/test/railtie_test.rb +31 -0
- data/test/rake_task_test.rb +57 -0
- data/test/resolver_test.rb +21 -0
- data/test/shared/shared_adapter_tests.rb +95 -0
- data/test/subdomain_elevator_test.rb +75 -0
- data/test/test_helper.rb +24 -0
- metadata +325 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
require_relative 'mocks/adapter_mock'
|
3
|
+
require 'innkeeper/elevators/generic'
|
4
|
+
|
5
|
+
class GenericElevatorTest < Minitest::Test
|
6
|
+
include AdapterMock
|
7
|
+
|
8
|
+
class MyElevator < Innkeeper::Elevators::Generic
|
9
|
+
def parse_tenant_name(*)
|
10
|
+
'tenant2'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def setup
|
15
|
+
@elevator = Innkeeper::Elevators::Generic.new(Proc.new{})
|
16
|
+
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_processor_is_called_if_given
|
21
|
+
elevator = Innkeeper::Elevators::Generic.new(Proc.new{}, Proc.new{'tenant1'})
|
22
|
+
|
23
|
+
with_adapter_mocked do |adapter|
|
24
|
+
adapter.expect :switch, true, ['tenant1']
|
25
|
+
|
26
|
+
elevator.call('HTTP_HOST' => 'foo.bar.com')
|
27
|
+
|
28
|
+
assert adapter.verify
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_raises_if_parse_tenant_name_not_implemented
|
33
|
+
assert_raises RuntimeError do
|
34
|
+
@elevator.call('HTTP_HOST' => 'foo.bar.com')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_switches_to_the_parsed_db_name
|
39
|
+
elevator = MyElevator.new(Proc.new{})
|
40
|
+
|
41
|
+
with_adapter_mocked do |adapter|
|
42
|
+
adapter.expect :switch, true, ['tenant2']
|
43
|
+
|
44
|
+
elevator.call('HTTP_HOST' => 'foo.bar.com')
|
45
|
+
|
46
|
+
assert adapter.verify
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_does_not_call_switch_if_no_database_given
|
51
|
+
app_mock = Minitest::Mock.new
|
52
|
+
app_mock.expect :call, true, [{'HTTP_HOST' => 'foo.bar.com'}]
|
53
|
+
elevator = MyElevator.new(app_mock, Proc.new{})
|
54
|
+
|
55
|
+
with_adapter_mocked do |adapter|
|
56
|
+
elevator.call('HTTP_HOST' => 'foo.bar.com')
|
57
|
+
|
58
|
+
assert adapter.verify
|
59
|
+
end
|
60
|
+
|
61
|
+
assert app_mock.verify
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
require_relative 'mocks/adapter_mock'
|
3
|
+
require 'innkeeper/elevators/host_hash'
|
4
|
+
|
5
|
+
class HostHashElevatorTest < Minitest::Test
|
6
|
+
include AdapterMock
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@elevator = Innkeeper::Elevators::HostHash.new(Proc.new{}, 'example.com' => 'example_tenant')
|
10
|
+
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_parses_host_from_domain_name
|
15
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com')
|
16
|
+
assert_equal 'example_tenant', @elevator.parse_tenant_name(request)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_raises_exception_if_no_host
|
20
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => '')
|
21
|
+
assert_raises Innkeeper::TenantNotFound do
|
22
|
+
@elevator.parse_tenant_name(request)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_raises_exception_if_host_not_found
|
27
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'example2.com')
|
28
|
+
assert_raises Innkeeper::TenantNotFound do
|
29
|
+
@elevator.parse_tenant_name(request)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_switches_to_proper_tenant
|
34
|
+
with_adapter_mocked do |adapter|
|
35
|
+
adapter.expect :switch, true, ['example_tenant']
|
36
|
+
|
37
|
+
@elevator.call('HTTP_HOST' => 'example.com')
|
38
|
+
|
39
|
+
assert adapter.verify
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require "minitest/autorun"
|
2
|
+
|
3
|
+
module Innkeeper
|
4
|
+
class Test < Minitest::Test
|
5
|
+
def setup_connection(db)
|
6
|
+
@config = Innkeeper::TestHelper.config['connections'][db].symbolize_keys
|
7
|
+
ActiveRecord::Base.establish_connection(@config)
|
8
|
+
# `establish_connection` sets @connection_specification_name on
|
9
|
+
# ActiveRecord::Base, this causes it to override our Thread local.
|
10
|
+
# `establish_connection` should never be used in a productiion app
|
11
|
+
# for this reason.
|
12
|
+
Innkeeper.connection_class.connection_specification_name = nil
|
13
|
+
Innkeeper.reset
|
14
|
+
end
|
15
|
+
|
16
|
+
def setup
|
17
|
+
Innkeeper::Tenant.reload!
|
18
|
+
@adapter = Innkeeper::Tenant.adapter
|
19
|
+
@tenant1 = self.class.next_db
|
20
|
+
@tenant2 = self.class.next_db
|
21
|
+
@adapter.create(@tenant1)
|
22
|
+
@adapter.create(@tenant2)
|
23
|
+
end
|
24
|
+
|
25
|
+
def teardown
|
26
|
+
@adapter.reset
|
27
|
+
|
28
|
+
tenants = [@tenant1, @tenant2]
|
29
|
+
|
30
|
+
if @adapter.class.name == "Innkeeper::Adapters::PostgresqlAdapter"
|
31
|
+
@postgres_dbs ? drop(tenants, :database) : drop(tenants, :schema)
|
32
|
+
else
|
33
|
+
drop(tenants)
|
34
|
+
end
|
35
|
+
|
36
|
+
Innkeeper.excluded_models.each do |excl|
|
37
|
+
excl.constantize.connection_specification_name = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
Innkeeper.connection_class.clear_all_connections!
|
41
|
+
# unless we remove the connection pools, the connection pools from
|
42
|
+
# previous tests containing configs with deleted databases,
|
43
|
+
# persist and cause bugs for future tests using the same
|
44
|
+
# host/adapter (so the spec name is the same)
|
45
|
+
Innkeeper.connection_class.connection_handler.tap do |ch|
|
46
|
+
ch.send(:owner_to_pool).each_key do |k|
|
47
|
+
ch.remove_connection(k) if k =~ /^_innkeeper/
|
48
|
+
end
|
49
|
+
end
|
50
|
+
Innkeeper.reset
|
51
|
+
Innkeeper::Tenant.reload!
|
52
|
+
end
|
53
|
+
|
54
|
+
def drop(tenants, type = nil)
|
55
|
+
meth = "drop"
|
56
|
+
meth += "_#{type}" if type
|
57
|
+
|
58
|
+
tenants.each{ |t| @adapter.send(meth, t) }
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.next_db
|
62
|
+
@@x ||= 0
|
63
|
+
"db%d" % @@x += 1
|
64
|
+
end
|
65
|
+
|
66
|
+
def tenant_is(tenant, for_model: Innkeeper.connection_class)
|
67
|
+
config = Innkeeper::Tenant.config_for(tenant)
|
68
|
+
|
69
|
+
if @adapter.class.name == "Innkeeper::Adapters::PostgresqlAdapter"
|
70
|
+
current_search_path = for_model.connection.schema_search_path
|
71
|
+
end
|
72
|
+
|
73
|
+
config[:database] == for_model.connection.current_database &&
|
74
|
+
(!current_search_path || (current_search_path == config[:schema_search_path]) || current_search_path == "\"$user\", public") &&
|
75
|
+
(for_model != Innkeeper.connection_class || Innkeeper::Tenant.current == tenant)
|
76
|
+
end
|
77
|
+
|
78
|
+
def assert_tenant_is(tenant, for_model: Innkeeper.connection_class)
|
79
|
+
res = tenant_is(tenant, for_model: for_model)
|
80
|
+
|
81
|
+
if !res && @adapter.class.name == "Innkeeper::Adapters::PostgresqlAdapter"
|
82
|
+
schema = for_model.connection.schema_search_path
|
83
|
+
end
|
84
|
+
|
85
|
+
assert res, "Expected: #{tenant}\nActual: #{{ db: for_model.connection.current_database, schema: schema }}"
|
86
|
+
end
|
87
|
+
|
88
|
+
def assert_received(klass, meth, count = 1)
|
89
|
+
migrator_mock = Minitest::Mock.new
|
90
|
+
count.times{ migrator_mock.expect meth, true }
|
91
|
+
klass.stub(meth, ->(*){ migrator_mock.send(meth) }){ yield }
|
92
|
+
|
93
|
+
assert migrator_mock.verify
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module AdapterMock
|
2
|
+
def with_adapter_mocked
|
3
|
+
adapter = Minitest::Mock.new
|
4
|
+
old_adapter = Thread.current[:innkeeper_adapter]
|
5
|
+
Thread.current[:innkeeper_adapter] = adapter
|
6
|
+
|
7
|
+
yield adapter
|
8
|
+
ensure
|
9
|
+
Thread.current[:innkeeper_adapter] = old_adapter
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
require 'innkeeper/resolvers/database'
|
3
|
+
|
4
|
+
class MultithreadingTest < Innkeeper::Test
|
5
|
+
def setup
|
6
|
+
setup_connection("mysql")
|
7
|
+
|
8
|
+
Innkeeper.configure do |config|
|
9
|
+
# to test in connection switching mode as if switching between hosts
|
10
|
+
config.force_reconnect_on_switch = true
|
11
|
+
config.pool_per_config = true
|
12
|
+
config.tenant_resolver = Innkeeper::Resolvers::Database
|
13
|
+
end
|
14
|
+
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_thread_safety_of_switching
|
19
|
+
assert_tenant_is(Innkeeper.default_tenant)
|
20
|
+
|
21
|
+
threads = []
|
22
|
+
100.times do
|
23
|
+
threads << Thread.new do
|
24
|
+
db = [@tenant1, @tenant2].sample
|
25
|
+
Innkeeper::Tenant.switch!(db)
|
26
|
+
|
27
|
+
assert_tenant_is(db)
|
28
|
+
|
29
|
+
Innkeeper.connection_class.clear_active_connections!
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
threads.each(&:join)
|
34
|
+
|
35
|
+
assert_tenant_is(Innkeeper.default_tenant)
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
require 'innkeeper/resolvers/database'
|
3
|
+
require_relative 'shared/shared_adapter_tests'
|
4
|
+
|
5
|
+
class Mysql2AdapterTest < Innkeeper::Test
|
6
|
+
include SharedAdapterTests
|
7
|
+
|
8
|
+
def setup
|
9
|
+
setup_connection("mysql")
|
10
|
+
|
11
|
+
Innkeeper.configure do |config|
|
12
|
+
config.tenant_resolver = Innkeeper::Resolvers::Database
|
13
|
+
end
|
14
|
+
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
require 'innkeeper/resolvers/schema'
|
3
|
+
require 'innkeeper/resolvers/database'
|
4
|
+
require_relative 'shared/shared_adapter_tests'
|
5
|
+
|
6
|
+
class PostgresqlAdapterTest < Innkeeper::Test
|
7
|
+
include SharedAdapterTests
|
8
|
+
|
9
|
+
def setup
|
10
|
+
setup_connection("postgresql")
|
11
|
+
|
12
|
+
Innkeeper.configure do |config|
|
13
|
+
config.tenant_resolver = Innkeeper::Resolvers::Schema
|
14
|
+
end
|
15
|
+
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
# idk why it broked :'(
|
20
|
+
# def test_postgres_database_resolver_reconnects
|
21
|
+
# Innkeeper.tenant_resolver = Innkeeper::Resolvers::Database
|
22
|
+
|
23
|
+
# @adapter.create("db_tenant")
|
24
|
+
|
25
|
+
# assert_tenant_is(Innkeeper.default_tenant)
|
26
|
+
|
27
|
+
# conn_id = Innkeeper.connection.object_id
|
28
|
+
|
29
|
+
# Innkeeper::Tenant.switch("db_tenant") do
|
30
|
+
# refute_equal conn_id, Innkeeper.connection.object_id
|
31
|
+
# assert_equal "db_tenant", Innkeeper.connection.current_database
|
32
|
+
# end
|
33
|
+
|
34
|
+
# assert_tenant_is(Innkeeper.default_tenant)
|
35
|
+
# ensure
|
36
|
+
# @adapter.drop_database("db_tenant")
|
37
|
+
# Innkeeper.tenant_resolver = Innkeeper::Resolvers::Schema
|
38
|
+
# end
|
39
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
require 'innkeeper/resolvers/database'
|
3
|
+
|
4
|
+
class RailtieTest < Minitest::Test
|
5
|
+
def test_railtie_does_not_hold_onto_connection
|
6
|
+
Innkeeper.configure do |config|
|
7
|
+
config.tenant_resolver = Innkeeper::Resolvers::Database
|
8
|
+
config.excluded_models = %w(Company)
|
9
|
+
end
|
10
|
+
|
11
|
+
Innkeeper.connection_class.connection_pool.disconnect!
|
12
|
+
|
13
|
+
before = Innkeeper.connection_class.connection_pool.stat.slice(:busy, :dead, :waiting)
|
14
|
+
|
15
|
+
Innkeeper::Railtie.prep
|
16
|
+
Innkeeper::Railtie.config.to_prepare_blocks.map(&:call)
|
17
|
+
|
18
|
+
after = Innkeeper.connection_class.connection_pool.stat.slice(:busy, :dead, :waiting)
|
19
|
+
|
20
|
+
assert_equal before, after
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_railtie_sets_default_configuration
|
24
|
+
Innkeeper::Railtie.prep
|
25
|
+
|
26
|
+
assert_equal [], Innkeeper.excluded_models
|
27
|
+
assert_equal false, Innkeeper.force_reconnect_on_switch
|
28
|
+
assert_equal false, Innkeeper.seed_after_create
|
29
|
+
assert_instance_of Innkeeper::Resolvers::Database, Innkeeper.tenant_resolver
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
require 'innkeeper/resolvers/database'
|
3
|
+
require 'rake'
|
4
|
+
|
5
|
+
class RakeTaskTest < Innkeeper::Test
|
6
|
+
def setup
|
7
|
+
setup_connection("mysql")
|
8
|
+
|
9
|
+
Innkeeper.configure do |config|
|
10
|
+
config.excluded_models = ["Company"]
|
11
|
+
config.tenant_names = lambda{ Company.pluck(:database) }
|
12
|
+
config.tenant_resolver = Innkeeper::Resolvers::Database
|
13
|
+
end
|
14
|
+
|
15
|
+
super
|
16
|
+
|
17
|
+
@rake = Rake::Application.new
|
18
|
+
Rake.application = @rake
|
19
|
+
Dummy::Application.load_tasks
|
20
|
+
|
21
|
+
# rails tasks running F up the schema...
|
22
|
+
Rake::Task.define_task('db:migrate')
|
23
|
+
Rake::Task.define_task('db:seed')
|
24
|
+
Rake::Task.define_task('db:rollback')
|
25
|
+
Rake::Task.define_task('db:migrate:up')
|
26
|
+
Rake::Task.define_task('db:migrate:down')
|
27
|
+
Rake::Task.define_task('db:migrate:redo')
|
28
|
+
|
29
|
+
@tenants = [@tenant1, @tenant2]
|
30
|
+
@tenants.each{ |t| Company.create(database: t) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def teardown
|
34
|
+
Rake.application = nil
|
35
|
+
Company.delete_all
|
36
|
+
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_all_databases_get_migrated
|
41
|
+
assert_received(Innkeeper::Migrator, :migrate, @tenants.size) do
|
42
|
+
@rake['innkeeper:migrate'].invoke
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_all_databases_get_rolled_back
|
47
|
+
assert_received(Innkeeper::Migrator, :rollback, @tenants.size) do
|
48
|
+
@rake['innkeeper:rollback'].invoke
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_all_databases_get_seeded
|
53
|
+
assert_received(Innkeeper::Tenant, :seed, @tenants.size) do
|
54
|
+
@rake['innkeeper:seed'].invoke
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
require 'innkeeper/resolvers/database'
|
3
|
+
require 'innkeeper/resolvers/schema'
|
4
|
+
|
5
|
+
class ResolverTest < Minitest::Test
|
6
|
+
def test_database_resolver
|
7
|
+
resolver = Innkeeper::Resolvers::Database.new(Innkeeper.connection_config)
|
8
|
+
new_config = resolver.resolve("foobar")
|
9
|
+
|
10
|
+
assert_equal "foobar", new_config[:database]
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_schema_resolver
|
14
|
+
Innkeeper.configure{ |config| config.persistent_schemas = ['a', 'b', 'c'] }
|
15
|
+
|
16
|
+
resolver = Innkeeper::Resolvers::Schema.new(Innkeeper.connection_config)
|
17
|
+
new_config = resolver.resolve("foobar")
|
18
|
+
|
19
|
+
assert_equal '"foobar", "a", "b", "c"', new_config[:schema_search_path]
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module SharedAdapterTests
|
2
|
+
def test_switch
|
3
|
+
assert_tenant_is(Innkeeper.default_tenant)
|
4
|
+
|
5
|
+
Innkeeper::Tenant.switch(@tenant1){
|
6
|
+
assert_tenant_is(@tenant1)
|
7
|
+
}
|
8
|
+
|
9
|
+
assert_tenant_is(Innkeeper.default_tenant)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_local_switch_doesnt_modify_connection
|
13
|
+
assert_tenant_is(Innkeeper.default_tenant)
|
14
|
+
|
15
|
+
conn_id = Innkeeper.connection.object_id
|
16
|
+
|
17
|
+
Innkeeper::Tenant.switch!(@tenant1)
|
18
|
+
|
19
|
+
assert_tenant_is(@tenant1)
|
20
|
+
assert_equal conn_id, Innkeeper.connection.object_id
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_remote_switch_modifies_connection
|
24
|
+
assert_tenant_is(Innkeeper.default_tenant)
|
25
|
+
|
26
|
+
conn_id = Innkeeper.connection.object_id
|
27
|
+
|
28
|
+
Innkeeper::Tenant.switch!(@config.dup.tap{ |c| c[:host] = 'localhost' })
|
29
|
+
|
30
|
+
assert_equal @config[:database], Innkeeper.connection.current_database
|
31
|
+
refute_equal conn_id, Innkeeper.connection.object_id
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_force_reconnect
|
35
|
+
Innkeeper.configure{ |config| config.force_reconnect_on_switch = true }
|
36
|
+
|
37
|
+
assert_tenant_is(Innkeeper.default_tenant)
|
38
|
+
|
39
|
+
conn_id = Innkeeper.connection.object_id
|
40
|
+
|
41
|
+
Innkeeper::Tenant.switch!(@tenant1)
|
42
|
+
|
43
|
+
assert_tenant_is(@tenant1)
|
44
|
+
refute_equal conn_id, Innkeeper.connection.object_id
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_switch_raises_error_for_unknown_database
|
48
|
+
assert_raises Innkeeper::TenantNotFound do
|
49
|
+
Innkeeper::Tenant.switch!("invalid")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_drop_raises_error_for_unknown_database
|
54
|
+
assert_raises Innkeeper::TenantNotFound do
|
55
|
+
if Innkeeper::Tenant.adapter.respond_to?(:drop_schema)
|
56
|
+
Innkeeper::Tenant.drop_schema("invalid")
|
57
|
+
else
|
58
|
+
Innkeeper::Tenant.drop("invalid")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_default_tenant_configuration_is_used
|
64
|
+
prev_default = Innkeeper.default_tenant
|
65
|
+
|
66
|
+
Innkeeper.configure do |config|
|
67
|
+
config.default_tenant = @tenant1
|
68
|
+
end
|
69
|
+
|
70
|
+
assert_equal @tenant1, Innkeeper.default_tenant
|
71
|
+
|
72
|
+
@adapter.reset
|
73
|
+
|
74
|
+
assert_tenant_is(@tenant1)
|
75
|
+
ensure
|
76
|
+
Innkeeper.default_tenant = prev_default
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_ActiveRecord_QueryCache_cleared_after_switching_databases
|
80
|
+
[@tenant1, @tenant2].each do |tenant|
|
81
|
+
Innkeeper::Tenant.switch(tenant) do
|
82
|
+
User.create!(name: tenant)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
Innkeeper.connection.enable_query_cache!
|
86
|
+
|
87
|
+
Innkeeper::Tenant.switch(@tenant1) do
|
88
|
+
assert User.find_by(name: @tenant1)
|
89
|
+
end
|
90
|
+
|
91
|
+
Innkeeper::Tenant.switch(@tenant2) do
|
92
|
+
assert_nil User.find_by(name: @tenant1)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|