ros-apartment 2.3.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE.md +21 -0
  3. data/.gitignore +15 -0
  4. data/.pryrc +3 -0
  5. data/.rspec +4 -0
  6. data/.travis.yml +65 -0
  7. data/Appraisals +71 -0
  8. data/Gemfile +10 -0
  9. data/Guardfile +24 -0
  10. data/HISTORY.md +398 -0
  11. data/README.md +576 -0
  12. data/Rakefile +128 -0
  13. data/TODO.md +51 -0
  14. data/apartment.gemspec +46 -0
  15. data/docker-compose.yml +33 -0
  16. data/gemfiles/rails_4_2.gemfile +23 -0
  17. data/gemfiles/rails_5_0.gemfile +22 -0
  18. data/gemfiles/rails_5_1.gemfile +22 -0
  19. data/gemfiles/rails_5_2.gemfile +18 -0
  20. data/gemfiles/rails_6_0.gemfile +22 -0
  21. data/gemfiles/rails_master.gemfile +22 -0
  22. data/lib/apartment.rb +118 -0
  23. data/lib/apartment/adapters/abstract_adapter.rb +269 -0
  24. data/lib/apartment/adapters/abstract_jdbc_adapter.rb +18 -0
  25. data/lib/apartment/adapters/jdbc_mysql_adapter.rb +19 -0
  26. data/lib/apartment/adapters/jdbc_postgresql_adapter.rb +56 -0
  27. data/lib/apartment/adapters/mysql2_adapter.rb +71 -0
  28. data/lib/apartment/adapters/postgis_adapter.rb +12 -0
  29. data/lib/apartment/adapters/postgresql_adapter.rb +236 -0
  30. data/lib/apartment/adapters/sqlite3_adapter.rb +56 -0
  31. data/lib/apartment/console.rb +12 -0
  32. data/lib/apartment/deprecation.rb +10 -0
  33. data/lib/apartment/elevators/domain.rb +22 -0
  34. data/lib/apartment/elevators/first_subdomain.rb +17 -0
  35. data/lib/apartment/elevators/generic.rb +32 -0
  36. data/lib/apartment/elevators/host.rb +30 -0
  37. data/lib/apartment/elevators/host_hash.rb +22 -0
  38. data/lib/apartment/elevators/subdomain.rb +62 -0
  39. data/lib/apartment/migrator.rb +51 -0
  40. data/lib/apartment/railtie.rb +67 -0
  41. data/lib/apartment/reloader.rb +21 -0
  42. data/lib/apartment/tasks/enhancements.rb +57 -0
  43. data/lib/apartment/tenant.rb +66 -0
  44. data/lib/apartment/version.rb +3 -0
  45. data/lib/generators/apartment/install/USAGE +5 -0
  46. data/lib/generators/apartment/install/install_generator.rb +10 -0
  47. data/lib/generators/apartment/install/templates/apartment.rb +109 -0
  48. data/lib/tasks/apartment.rake +145 -0
  49. data/spec/adapters/jdbc_mysql_adapter_spec.rb +19 -0
  50. data/spec/adapters/jdbc_postgresql_adapter_spec.rb +41 -0
  51. data/spec/adapters/mysql2_adapter_spec.rb +59 -0
  52. data/spec/adapters/postgresql_adapter_spec.rb +61 -0
  53. data/spec/adapters/sqlite3_adapter_spec.rb +83 -0
  54. data/spec/apartment_spec.rb +11 -0
  55. data/spec/config/database.yml.sample +49 -0
  56. data/spec/dummy/Rakefile +7 -0
  57. data/spec/dummy/app/controllers/application_controller.rb +6 -0
  58. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  59. data/spec/dummy/app/models/company.rb +3 -0
  60. data/spec/dummy/app/models/user.rb +3 -0
  61. data/spec/dummy/app/views/application/index.html.erb +1 -0
  62. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  63. data/spec/dummy/config.ru +4 -0
  64. data/spec/dummy/config/application.rb +49 -0
  65. data/spec/dummy/config/boot.rb +11 -0
  66. data/spec/dummy/config/database.yml.sample +44 -0
  67. data/spec/dummy/config/environment.rb +5 -0
  68. data/spec/dummy/config/environments/development.rb +28 -0
  69. data/spec/dummy/config/environments/production.rb +51 -0
  70. data/spec/dummy/config/environments/test.rb +34 -0
  71. data/spec/dummy/config/initializers/apartment.rb +4 -0
  72. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  73. data/spec/dummy/config/initializers/inflections.rb +10 -0
  74. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  75. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  76. data/spec/dummy/config/initializers/session_store.rb +8 -0
  77. data/spec/dummy/config/locales/en.yml +5 -0
  78. data/spec/dummy/config/routes.rb +3 -0
  79. data/spec/dummy/db/migrate/20110613152810_create_dummy_models.rb +39 -0
  80. data/spec/dummy/db/migrate/20111202022214_create_table_books.rb +14 -0
  81. data/spec/dummy/db/migrate/20180415260934_create_public_tokens.rb +13 -0
  82. data/spec/dummy/db/schema.rb +55 -0
  83. data/spec/dummy/db/seeds.rb +5 -0
  84. data/spec/dummy/db/seeds/import.rb +5 -0
  85. data/spec/dummy/public/404.html +26 -0
  86. data/spec/dummy/public/422.html +26 -0
  87. data/spec/dummy/public/500.html +26 -0
  88. data/spec/dummy/public/favicon.ico +0 -0
  89. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  90. data/spec/dummy/script/rails +6 -0
  91. data/spec/dummy_engine/.gitignore +8 -0
  92. data/spec/dummy_engine/Gemfile +15 -0
  93. data/spec/dummy_engine/Rakefile +34 -0
  94. data/spec/dummy_engine/bin/rails +12 -0
  95. data/spec/dummy_engine/config/initializers/apartment.rb +51 -0
  96. data/spec/dummy_engine/dummy_engine.gemspec +24 -0
  97. data/spec/dummy_engine/lib/dummy_engine.rb +4 -0
  98. data/spec/dummy_engine/lib/dummy_engine/engine.rb +4 -0
  99. data/spec/dummy_engine/lib/dummy_engine/version.rb +3 -0
  100. data/spec/dummy_engine/test/dummy/Rakefile +6 -0
  101. data/spec/dummy_engine/test/dummy/config.ru +4 -0
  102. data/spec/dummy_engine/test/dummy/config/application.rb +22 -0
  103. data/spec/dummy_engine/test/dummy/config/boot.rb +5 -0
  104. data/spec/dummy_engine/test/dummy/config/database.yml +25 -0
  105. data/spec/dummy_engine/test/dummy/config/environment.rb +5 -0
  106. data/spec/dummy_engine/test/dummy/config/environments/development.rb +37 -0
  107. data/spec/dummy_engine/test/dummy/config/environments/production.rb +78 -0
  108. data/spec/dummy_engine/test/dummy/config/environments/test.rb +39 -0
  109. data/spec/dummy_engine/test/dummy/config/initializers/assets.rb +8 -0
  110. data/spec/dummy_engine/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  111. data/spec/dummy_engine/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  112. data/spec/dummy_engine/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  113. data/spec/dummy_engine/test/dummy/config/initializers/inflections.rb +16 -0
  114. data/spec/dummy_engine/test/dummy/config/initializers/mime_types.rb +4 -0
  115. data/spec/dummy_engine/test/dummy/config/initializers/session_store.rb +3 -0
  116. data/spec/dummy_engine/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  117. data/spec/dummy_engine/test/dummy/config/locales/en.yml +23 -0
  118. data/spec/dummy_engine/test/dummy/config/routes.rb +56 -0
  119. data/spec/dummy_engine/test/dummy/config/secrets.yml +22 -0
  120. data/spec/examples/connection_adapter_examples.rb +42 -0
  121. data/spec/examples/generic_adapter_custom_configuration_example.rb +95 -0
  122. data/spec/examples/generic_adapter_examples.rb +163 -0
  123. data/spec/examples/schema_adapter_examples.rb +234 -0
  124. data/spec/integration/apartment_rake_integration_spec.rb +107 -0
  125. data/spec/integration/query_caching_spec.rb +81 -0
  126. data/spec/integration/use_within_an_engine_spec.rb +28 -0
  127. data/spec/schemas/v1.rb +16 -0
  128. data/spec/schemas/v2.rb +43 -0
  129. data/spec/schemas/v3.rb +49 -0
  130. data/spec/spec_helper.rb +61 -0
  131. data/spec/support/apartment_helpers.rb +43 -0
  132. data/spec/support/capybara_sessions.rb +15 -0
  133. data/spec/support/config.rb +10 -0
  134. data/spec/support/contexts.rb +52 -0
  135. data/spec/support/requirements.rb +35 -0
  136. data/spec/support/setup.rb +46 -0
  137. data/spec/tasks/apartment_rake_spec.rb +129 -0
  138. data/spec/tenant_spec.rb +190 -0
  139. data/spec/unit/config_spec.rb +112 -0
  140. data/spec/unit/elevators/domain_spec.rb +32 -0
  141. data/spec/unit/elevators/first_subdomain_spec.rb +24 -0
  142. data/spec/unit/elevators/generic_spec.rb +54 -0
  143. data/spec/unit/elevators/host_hash_spec.rb +32 -0
  144. data/spec/unit/elevators/host_spec.rb +89 -0
  145. data/spec/unit/elevators/subdomain_spec.rb +76 -0
  146. data/spec/unit/migrator_spec.rb +77 -0
  147. data/spec/unit/reloader_spec.rb +24 -0
  148. metadata +487 -0
@@ -0,0 +1,39 @@
1
+ Rails.application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb.
3
+
4
+ # The test environment is used exclusively to run your application's
5
+ # test suite. You never need to work with it otherwise. Remember that
6
+ # your test database is "scratch space" for the test suite and is wiped
7
+ # and recreated between test runs. Don't rely on the data there!
8
+ config.cache_classes = true
9
+
10
+ # Do not eager load code on boot. This avoids loading your whole application
11
+ # just for the purpose of running a single test. If you are using a tool that
12
+ # preloads Rails for running tests, you may have to set it to true.
13
+ config.eager_load = false
14
+
15
+ # Configure static asset server for tests with Cache-Control for performance.
16
+ config.serve_static_assets = true
17
+ config.static_cache_control = 'public, max-age=3600'
18
+
19
+ # Show full error reports and disable caching.
20
+ config.consider_all_requests_local = true
21
+ config.action_controller.perform_caching = false
22
+
23
+ # Raise exceptions instead of rendering exception templates.
24
+ config.action_dispatch.show_exceptions = false
25
+
26
+ # Disable request forgery protection in test environment.
27
+ config.action_controller.allow_forgery_protection = false
28
+
29
+ # Tell Action Mailer not to deliver emails to the real world.
30
+ # The :test delivery method accumulates sent emails in the
31
+ # ActionMailer::Base.deliveries array.
32
+ config.action_mailer.delivery_method = :test
33
+
34
+ # Print deprecation notices to the stderr.
35
+ config.active_support.deprecation = :stderr
36
+
37
+ # Raises error for missing translations
38
+ # config.action_view.raise_on_missing_translations = true
39
+ end
@@ -0,0 +1,8 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Version of your assets, change this if you want to expire all your assets.
4
+ Rails.application.config.assets.version = '1.0'
5
+
6
+ # Precompile additional assets.
7
+ # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
8
+ # Rails.application.config.assets.precompile += %w( search.js )
@@ -0,0 +1,7 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4
+ # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5
+
6
+ # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7
+ # Rails.backtrace_cleaner.remove_silencers!
@@ -0,0 +1,3 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ Rails.application.config.action_dispatch.cookies_serializer = :json
@@ -0,0 +1,4 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Configure sensitive parameters which will be filtered from the log file.
4
+ Rails.application.config.filter_parameters += [:password]
@@ -0,0 +1,16 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Add new inflection rules using the following format. Inflections
4
+ # are locale specific, and you may define rules for as many different
5
+ # locales as you wish. All of these examples are active by default:
6
+ # ActiveSupport::Inflector.inflections(:en) do |inflect|
7
+ # inflect.plural /^(ox)$/i, '\1en'
8
+ # inflect.singular /^(ox)en/i, '\1'
9
+ # inflect.irregular 'person', 'people'
10
+ # inflect.uncountable %w( fish sheep )
11
+ # end
12
+
13
+ # These inflection rules are supported but not enabled by default:
14
+ # ActiveSupport::Inflector.inflections(:en) do |inflect|
15
+ # inflect.acronym 'RESTful'
16
+ # end
@@ -0,0 +1,4 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Add new mime types for use in respond_to blocks:
4
+ # Mime::Type.register "text/richtext", :rtf
@@ -0,0 +1,3 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ Rails.application.config.session_store :cookie_store, key: '_dummy_session'
@@ -0,0 +1,14 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # This file contains settings for ActionController::ParamsWrapper which
4
+ # is enabled by default.
5
+
6
+ # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7
+ ActiveSupport.on_load(:action_controller) do
8
+ wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
9
+ end
10
+
11
+ # To enable root element in JSON for ActiveRecord objects.
12
+ # ActiveSupport.on_load(:active_record) do
13
+ # self.include_root_in_json = true
14
+ # end
@@ -0,0 +1,23 @@
1
+ # Files in the config/locales directory are used for internationalization
2
+ # and are automatically loaded by Rails. If you want to use locales other
3
+ # than English, add the necessary files in this directory.
4
+ #
5
+ # To use the locales, use `I18n.t`:
6
+ #
7
+ # I18n.t 'hello'
8
+ #
9
+ # In views, this is aliased to just `t`:
10
+ #
11
+ # <%= t('hello') %>
12
+ #
13
+ # To use a different locale, set it with `I18n.locale`:
14
+ #
15
+ # I18n.locale = :es
16
+ #
17
+ # This would use the information in config/locales/es.yml.
18
+ #
19
+ # To learn more, please read the Rails Internationalization guide
20
+ # available at http://guides.rubyonrails.org/i18n.html.
21
+
22
+ en:
23
+ hello: "Hello world"
@@ -0,0 +1,56 @@
1
+ Rails.application.routes.draw do
2
+ # The priority is based upon order of creation: first created -> highest priority.
3
+ # See how all your routes lay out with "rake routes".
4
+
5
+ # You can have the root of your site routed with "root"
6
+ # root 'welcome#index'
7
+
8
+ # Example of regular route:
9
+ # get 'products/:id' => 'catalog#view'
10
+
11
+ # Example of named route that can be invoked with purchase_url(id: product.id)
12
+ # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
13
+
14
+ # Example resource route (maps HTTP verbs to controller actions automatically):
15
+ # resources :products
16
+
17
+ # Example resource route with options:
18
+ # resources :products do
19
+ # member do
20
+ # get 'short'
21
+ # post 'toggle'
22
+ # end
23
+ #
24
+ # collection do
25
+ # get 'sold'
26
+ # end
27
+ # end
28
+
29
+ # Example resource route with sub-resources:
30
+ # resources :products do
31
+ # resources :comments, :sales
32
+ # resource :seller
33
+ # end
34
+
35
+ # Example resource route with more complex sub-resources:
36
+ # resources :products do
37
+ # resources :comments
38
+ # resources :sales do
39
+ # get 'recent', on: :collection
40
+ # end
41
+ # end
42
+
43
+ # Example resource route with concerns:
44
+ # concern :toggleable do
45
+ # post 'toggle'
46
+ # end
47
+ # resources :posts, concerns: :toggleable
48
+ # resources :photos, concerns: :toggleable
49
+
50
+ # Example resource route within a namespace:
51
+ # namespace :admin do
52
+ # # Directs /admin/products/* to Admin::ProductsController
53
+ # # (app/controllers/admin/products_controller.rb)
54
+ # resources :products
55
+ # end
56
+ end
@@ -0,0 +1,22 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Your secret key is used for verifying the integrity of signed cookies.
4
+ # If you change this key, all old signed cookies will become invalid!
5
+
6
+ # Make sure the secret is at least 30 characters and all random,
7
+ # no regular words or you'll be exposed to dictionary attacks.
8
+ # You can use `rake secret` to generate a secure secret key.
9
+
10
+ # Make sure the secrets in this file are kept private
11
+ # if you're sharing your code publicly.
12
+
13
+ development:
14
+ secret_key_base: bb62b819b585a74e69c797f9d03d5a004d8fe82a8e7a7da6fa2f7923030713b7b087c12cc7a918e71073c38afb343f7223d22ba3f1b223b7e76dbf8d5b65fa2c
15
+
16
+ test:
17
+ secret_key_base: 67945d3b189c71dffef98de2bb7c14d6fb059679c115ca3cddf65c88babe130afe4d583560d0e308b017dd76ce305bef4159d876de9fd893952d9cbf269c8476
18
+
19
+ # Do not keep production secrets in the repository,
20
+ # instead read values from the environment.
21
+ production:
22
+ secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for "a connection based apartment adapter" do
4
+ include Apartment::Spec::AdapterRequirements
5
+
6
+ let(:default_tenant){ subject.switch{ ActiveRecord::Base.connection.current_database } }
7
+
8
+ describe "#init" do
9
+ after do
10
+ # Apartment::Tenant.init creates per model connection.
11
+ # Remove the connection after testing not to unintentionally keep the connection across tests.
12
+ Apartment.excluded_models.each do |excluded_model|
13
+ excluded_model.constantize.remove_connection
14
+ end
15
+ end
16
+
17
+ it "should process model exclusions" do
18
+ Apartment.configure do |config|
19
+ config.excluded_models = ["Company"]
20
+ end
21
+ Apartment::Tenant.init
22
+
23
+ expect(Company.connection.object_id).not_to eq(ActiveRecord::Base.connection.object_id)
24
+ end
25
+ end
26
+
27
+ describe "#drop" do
28
+ it "should raise an error for unknown database" do
29
+ expect {
30
+ subject.drop 'unknown_database'
31
+ }.to raise_error(Apartment::TenantNotFound)
32
+ end
33
+ end
34
+
35
+ describe "#switch!" do
36
+ it "should raise an error if database is invalid" do
37
+ expect {
38
+ subject.switch! 'unknown_database'
39
+ }.to raise_error(Apartment::TenantNotFound)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for "a generic apartment adapter able to handle custom configuration" do
4
+
5
+ let(:custom_tenant_name) { 'test_tenantwwww' }
6
+ let(:db) { |example| example.metadata[:database]}
7
+ let(:custom_tenant_names) do
8
+ {
9
+ custom_tenant_name => get_custom_db_conf
10
+ }
11
+ end
12
+
13
+ before do
14
+ Apartment.tenant_names = custom_tenant_names
15
+ Apartment.with_multi_server_setup = true
16
+ end
17
+
18
+ after do
19
+ Apartment.with_multi_server_setup = false
20
+ end
21
+
22
+ context "database key taken from specific config" do
23
+
24
+ let(:expected_args) { get_custom_db_conf }
25
+
26
+ describe "#create" do
27
+ it "should establish_connection with the separate connection with expected args" do
28
+ expect(Apartment::Adapters::AbstractAdapter::SeparateDbConnectionHandler).to receive(:establish_connection).with(expected_args).and_call_original
29
+
30
+ # because we dont have another server to connect to it errors
31
+ # what matters is establish_connection receives proper args
32
+ expect { subject.create(custom_tenant_name) }.to raise_error(Apartment::TenantExists)
33
+ end
34
+ end
35
+
36
+ describe "#drop" do
37
+ it "should establish_connection with the separate connection with expected args" do
38
+ expect(Apartment::Adapters::AbstractAdapter::SeparateDbConnectionHandler).to receive(:establish_connection).with(expected_args).and_call_original
39
+
40
+ # because we dont have another server to connect to it errors
41
+ # what matters is establish_connection receives proper args
42
+ expect { subject.drop(custom_tenant_name) }.to raise_error(Apartment::TenantNotFound)
43
+ end
44
+ end
45
+ end
46
+
47
+ context "database key from tenant name" do
48
+
49
+ let(:expected_args) {
50
+ get_custom_db_conf.tap {|args| args.delete(:database) }
51
+ }
52
+
53
+ describe "#switch!" do
54
+
55
+ it "should connect to new db" do
56
+ expect(Apartment).to receive(:establish_connection) do |args|
57
+ db_name = args.delete(:database)
58
+
59
+ expect(args).to eq expected_args
60
+ expect(db_name).to match custom_tenant_name
61
+
62
+ # we only need to check args, then we short circuit
63
+ # in order to avoid the mess due to the `establish_connection` override
64
+ raise ActiveRecord::ActiveRecordError
65
+ end
66
+
67
+ expect { subject.switch!(custom_tenant_name) }.to raise_error(Apartment::TenantNotFound)
68
+ end
69
+ end
70
+ end
71
+
72
+ def specific_connection
73
+ {
74
+ postgresql: {
75
+ adapter: 'postgresql',
76
+ database: 'override_database',
77
+ password: 'override_password',
78
+ username: 'overridepostgres'
79
+ },
80
+ mysql: {
81
+ adapter: 'mysql2',
82
+ database: 'override_database',
83
+ username: 'root'
84
+ },
85
+ sqlite: {
86
+ adapter: 'sqlite3',
87
+ database: 'override_database'
88
+ }
89
+ }
90
+ end
91
+
92
+ def get_custom_db_conf
93
+ specific_connection[db.to_sym].with_indifferent_access
94
+ end
95
+ end
@@ -0,0 +1,163 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for "a generic apartment adapter" do
4
+ include Apartment::Spec::AdapterRequirements
5
+
6
+ before {
7
+ Apartment.prepend_environment = false
8
+ Apartment.append_environment = false
9
+ }
10
+
11
+ describe "#init" do
12
+ it "should not retain a connection after railtie" do
13
+ # this test should work on rails >= 4, the connection pool code is
14
+ # completely different for 3.2 so we'd have to have a messy conditional..
15
+ unless Rails::VERSION::MAJOR < 4
16
+ ActiveRecord::Base.connection_pool.disconnect!
17
+
18
+ Apartment::Railtie.config.to_prepare_blocks.map(&:call)
19
+
20
+ num_available_connections = Apartment.connection_class.connection_pool
21
+ .instance_variable_get(:@available)
22
+ .instance_variable_get(:@queue)
23
+ .size
24
+
25
+ expect(num_available_connections).to eq(1)
26
+ end
27
+ end
28
+ end
29
+
30
+ #
31
+ # Creates happen already in our before_filter
32
+ #
33
+ describe "#create" do
34
+
35
+ it "should create the new databases" do
36
+ expect(tenant_names).to include(db1)
37
+ expect(tenant_names).to include(db2)
38
+ end
39
+
40
+ it "should load schema.rb to new schema" do
41
+ subject.switch(db1) do
42
+ expect(connection.tables).to include('companies')
43
+ end
44
+ end
45
+
46
+ it "should yield to block if passed and reset" do
47
+ subject.drop(db2) # so we don't get errors on creation
48
+
49
+ @count = 0 # set our variable so its visible in and outside of blocks
50
+
51
+ subject.create(db2) do
52
+ @count = User.count
53
+ expect(subject.current).to eq(db2)
54
+ User.create
55
+ end
56
+
57
+ expect(subject.current).not_to eq(db2)
58
+
59
+ subject.switch(db2){ expect(User.count).to eq(@count + 1) }
60
+ end
61
+
62
+ it "should raise error when the schema.rb is missing unless Apartment.use_sql is set to true" do
63
+ next if Apartment.use_sql
64
+
65
+ subject.drop(db1)
66
+ begin
67
+ Dir.mktmpdir do |tmpdir|
68
+ Apartment.database_schema_file = "#{tmpdir}/schema.rb"
69
+ expect {
70
+ subject.create(db1)
71
+ }.to raise_error(Apartment::FileNotFound)
72
+ end
73
+ ensure
74
+ Apartment.remove_instance_variable(:@database_schema_file)
75
+ end
76
+ end
77
+ end
78
+
79
+ describe "#drop" do
80
+ it "should remove the db" do
81
+ subject.drop db1
82
+ expect(tenant_names).not_to include(db1)
83
+ end
84
+ end
85
+
86
+ describe "#switch!" do
87
+ it "should connect to new db" do
88
+ subject.switch!(db1)
89
+ expect(subject.current).to eq(db1)
90
+ end
91
+
92
+ it "should reset connection if database is nil" do
93
+ subject.switch!
94
+ expect(subject.current).to eq(default_tenant)
95
+ end
96
+
97
+ it "should raise an error if database is invalid" do
98
+ expect {
99
+ subject.switch! 'unknown_database'
100
+ }.to raise_error(Apartment::ApartmentError)
101
+ end
102
+ end
103
+
104
+ describe "#switch" do
105
+ it "connects and resets the tenant" do
106
+ subject.switch(db1) do
107
+ expect(subject.current).to eq(db1)
108
+ end
109
+ expect(subject.current).to eq(default_tenant)
110
+ end
111
+
112
+ # We're often finding when using Apartment in tests, the `current` (ie the previously connect to db)
113
+ # gets dropped, but switch will try to return to that db in a test. We should just reset if it doesn't exist
114
+ it "should not throw exception if current is no longer accessible" do
115
+ subject.switch!(db2)
116
+
117
+ expect {
118
+ subject.switch(db1){ subject.drop(db2) }
119
+ }.to_not raise_error
120
+ end
121
+ end
122
+
123
+ describe "#reset" do
124
+ it "should reset connection" do
125
+ subject.switch!(db1)
126
+ subject.reset
127
+ expect(subject.current).to eq(default_tenant)
128
+ end
129
+ end
130
+
131
+ describe "#current" do
132
+ it "should return the current db name" do
133
+ subject.switch!(db1)
134
+ expect(subject.current).to eq(db1)
135
+ end
136
+ end
137
+
138
+ describe "#each" do
139
+ it "iterates over each tenant by default" do
140
+ result = []
141
+ Apartment.tenant_names = [db2, db1]
142
+
143
+ subject.each do |tenant|
144
+ result << tenant
145
+ expect(subject.current).to eq(tenant)
146
+ end
147
+
148
+ expect(result).to eq([db2, db1])
149
+ end
150
+
151
+ it "iterates over the given tenants" do
152
+ result = []
153
+ Apartment.tenant_names = [db2]
154
+
155
+ subject.each([db2]) do |tenant|
156
+ result << tenant
157
+ expect(subject.current).to eq(tenant)
158
+ end
159
+
160
+ expect(result).to eq([db2])
161
+ end
162
+ end
163
+ end