22 |
We're sorry, but something went wrong.
23 |
We've been notified about this issue and we'll take a look at it shortly.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/spec/dummy/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/influitive/apartment/f266f73e58835f94e4ec7c16f28443fe5eada1ac/spec/dummy/public/favicon.ico
--------------------------------------------------------------------------------
/spec/dummy/public/stylesheets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/influitive/apartment/f266f73e58835f94e4ec7c16f28443fe5eada1ac/spec/dummy/public/stylesheets/.gitkeep
--------------------------------------------------------------------------------
/spec/dummy/script/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3 |
4 | APP_PATH = File.expand_path('../../config/application', __FILE__)
5 | require File.expand_path('../../config/boot', __FILE__)
6 | require 'rails/commands'
7 |
--------------------------------------------------------------------------------
/spec/dummy_engine/.gitignore:
--------------------------------------------------------------------------------
1 | .bundle/
2 | log/*.log
3 | pkg/
4 | test/dummy/db/*.sqlite3
5 | test/dummy/db/*.sqlite3-journal
6 | test/dummy/log/*.log
7 | test/dummy/tmp/
8 | test/dummy/.sass-cache
9 |
--------------------------------------------------------------------------------
/spec/dummy_engine/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | # Declare your gem's dependencies in dummy_engine.gemspec.
4 | # Bundler will treat runtime dependencies like base dependencies, and
5 | # development dependencies will be added by default to the :development group.
6 | gemspec
7 |
8 | # Declare any dependencies that are still in development here instead of in
9 | # your gemspec. These might include edge Rails or gems from your path or
10 | # Git. Remember to move these dependencies to your gemspec before releasing
11 | # your gem to rubygems.org.
12 |
13 | # To use debugger
14 | # gem 'debugger'
15 | gem 'apartment', path: '../../'
16 |
--------------------------------------------------------------------------------
/spec/dummy_engine/Rakefile:
--------------------------------------------------------------------------------
1 | begin
2 | require 'bundler/setup'
3 | rescue LoadError
4 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5 | end
6 |
7 | require 'rdoc/task'
8 |
9 | RDoc::Task.new(:rdoc) do |rdoc|
10 | rdoc.rdoc_dir = 'rdoc'
11 | rdoc.title = 'DummyEngine'
12 | rdoc.options << '--line-numbers'
13 | rdoc.rdoc_files.include('README.rdoc')
14 | rdoc.rdoc_files.include('lib/**/*.rb')
15 | end
16 |
17 | APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18 | load 'rails/tasks/engine.rake'
19 |
20 |
21 |
22 | Bundler::GemHelper.install_tasks
23 |
24 | require 'rake/testtask'
25 |
26 | Rake::TestTask.new(:test) do |t|
27 | t.libs << 'lib'
28 | t.libs << 'test'
29 | t.pattern = 'test/**/*_test.rb'
30 | t.verbose = false
31 | end
32 |
33 |
34 | task default: :test
35 |
--------------------------------------------------------------------------------
/spec/dummy_engine/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
3 |
4 | ENGINE_ROOT = File.expand_path('../..', __FILE__)
5 | ENGINE_PATH = File.expand_path('../../lib/dummy_engine/engine', __FILE__)
6 |
7 | # Set up gems listed in the Gemfile.
8 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
9 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
10 |
11 | require 'rails/all'
12 | require 'rails/engine/commands'
13 |
--------------------------------------------------------------------------------
/spec/dummy_engine/config/initializers/apartment.rb:
--------------------------------------------------------------------------------
1 | # Require whichever elevator you're using below here...
2 | #
3 | # require 'apartment/elevators/generic'
4 | # require 'apartment/elevators/domain'
5 | require 'apartment/elevators/subdomain'
6 |
7 | #
8 | # Apartment Configuration
9 | #
10 | Apartment.configure do |config|
11 |
12 | # These models will not be multi-tenanted,
13 | # but remain in the global (public) namespace
14 | #
15 | # An example might be a Customer or Tenant model that stores each tenant information
16 | # ex:
17 | #
18 | # config.excluded_models = %w{Tenant}
19 | #
20 | config.excluded_models = %w{}
21 |
22 | # use postgres schemas?
23 | config.use_schemas = true
24 |
25 | # use raw SQL dumps for creating postgres schemas? (only appies with use_schemas set to true)
26 | #config.use_sql = true
27 |
28 | # configure persistent schemas (E.g. hstore )
29 | # config.persistent_schemas = %w{ hstore }
30 |
31 | # add the Rails environment to database names?
32 | # config.prepend_environment = true
33 | # config.append_environment = true
34 |
35 | # supply list of database names for migrations to run on
36 | # config.tenant_names = lambda{ ToDo_Tenant_Or_User_Model.pluck :database }
37 |
38 | # Specify a connection other than ActiveRecord::Base for apartment to use (only needed if your models are using a different connection)
39 | # config.connection_class = ActiveRecord::Base
40 | end
41 |
42 | ##
43 | # Elevator Configuration
44 |
45 | # Rails.application.config.middleware.use Apartment::Elevators::Generic, lambda { |request|
46 | # # TODO: supply generic implementation
47 | # }
48 |
49 | # Rails.application.config.middleware.use Apartment::Elevators::Domain
50 |
51 | Rails.application.config.middleware.use Apartment::Elevators::Subdomain
52 |
--------------------------------------------------------------------------------
/spec/dummy_engine/dummy_engine.gemspec:
--------------------------------------------------------------------------------
1 | $:.push File.expand_path("../lib", __FILE__)
2 |
3 | # Maintain your gem's version:
4 | require "dummy_engine/version"
5 |
6 | # Describe your gem and declare its dependencies:
7 | Gem::Specification.new do |s|
8 | s.name = "dummy_engine"
9 | s.version = DummyEngine::VERSION
10 | s.authors = ["Your name"]
11 | s.email = ["Your email"]
12 | s.homepage = ""
13 | s.summary = "Summary of DummyEngine."
14 | s.description = "Description of DummyEngine."
15 | s.license = "MIT"
16 |
17 | s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"]
18 | s.test_files = Dir["test/**/*"]
19 |
20 | s.add_dependency "rails", "~> 4.1.6"
21 | s.add_dependency "apartment"
22 |
23 | s.add_development_dependency "sqlite3"
24 | end
25 |
--------------------------------------------------------------------------------
/spec/dummy_engine/lib/dummy_engine.rb:
--------------------------------------------------------------------------------
1 | require "dummy_engine/engine"
2 |
3 | module DummyEngine
4 | end
5 |
--------------------------------------------------------------------------------
/spec/dummy_engine/lib/dummy_engine/engine.rb:
--------------------------------------------------------------------------------
1 | module DummyEngine
2 | class Engine < ::Rails::Engine
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/spec/dummy_engine/lib/dummy_engine/version.rb:
--------------------------------------------------------------------------------
1 | module DummyEngine
2 | VERSION = "0.0.1"
3 | end
4 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require File.expand_path('../config/application', __FILE__)
5 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require ::File.expand_path('../config/environment', __FILE__)
4 | run Rails.application
5 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 |
3 | require 'rails/all'
4 |
5 | Bundler.require(*Rails.groups)
6 | require "dummy_engine"
7 |
8 | module Dummy
9 | class Application < Rails::Application
10 | # Settings in config/environments/* take precedence over those specified here.
11 | # Application configuration should go into files in config/initializers
12 | # -- all .rb files in that directory are automatically loaded.
13 |
14 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
15 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
16 | # config.time_zone = 'Central Time (US & Canada)'
17 |
18 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
19 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
20 | # config.i18n.default_locale = :de
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/boot.rb:
--------------------------------------------------------------------------------
1 | # Set up gems listed in the Gemfile.
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
3 |
4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5 | $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)
6 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/database.yml:
--------------------------------------------------------------------------------
1 | # SQLite version 3.x
2 | # gem install sqlite3
3 | #
4 | # Ensure the SQLite 3 gem is defined in your Gemfile
5 | # gem 'sqlite3'
6 | #
7 | default: &default
8 | adapter: sqlite3
9 | pool: 5
10 | timeout: 5000
11 |
12 | development:
13 | <<: *default
14 | database: db/development.sqlite3
15 |
16 | # Warning: The database defined as "test" will be erased and
17 | # re-generated from your development database when you run "rake".
18 | # Do not set this db to the same as development or production.
19 | test:
20 | <<: *default
21 | database: db/test.sqlite3
22 |
23 | production:
24 | <<: *default
25 | database: db/production.sqlite3
26 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require File.expand_path('../application', __FILE__)
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Do not eager load code on boot.
10 | config.eager_load = false
11 |
12 | # Show full error reports and disable caching.
13 | config.consider_all_requests_local = true
14 | config.action_controller.perform_caching = false
15 |
16 | # Don't care if the mailer can't send.
17 | config.action_mailer.raise_delivery_errors = false
18 |
19 | # Print deprecation notices to the Rails logger.
20 | config.active_support.deprecation = :log
21 |
22 | # Raise an error on page load if there are pending migrations.
23 | config.active_record.migration_error = :page_load
24 |
25 | # Debug mode disables concatenation and preprocessing of assets.
26 | # This option may cause significant delays in view rendering with a large
27 | # number of complex assets.
28 | config.assets.debug = true
29 |
30 | # Adds additional error checking when serving assets at runtime.
31 | # Checks for improperly declared sprockets dependencies.
32 | # Raises helpful error messages.
33 | config.assets.raise_runtime_errors = true
34 |
35 | # Raises error for missing translations
36 | # config.action_view.raise_on_missing_translations = true
37 | end
38 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # Code is not reloaded between requests.
5 | config.cache_classes = true
6 |
7 | # Eager load code on boot. This eager loads most of Rails and
8 | # your application in memory, allowing both threaded web servers
9 | # and those relying on copy on write to perform better.
10 | # Rake tasks automatically ignore this option for performance.
11 | config.eager_load = true
12 |
13 | # Full error reports are disabled and caching is turned on.
14 | config.consider_all_requests_local = false
15 | config.action_controller.perform_caching = true
16 |
17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application
18 | # Add `rack-cache` to your Gemfile before enabling this.
19 | # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid.
20 | # config.action_dispatch.rack_cache = true
21 |
22 | # Disable Rails's static asset server (Apache or nginx will already do this).
23 | config.serve_static_assets = false
24 |
25 | # Compress JavaScripts and CSS.
26 | config.assets.js_compressor = :uglifier
27 | # config.assets.css_compressor = :sass
28 |
29 | # Do not fallback to assets pipeline if a precompiled asset is missed.
30 | config.assets.compile = false
31 |
32 | # Generate digests for assets URLs.
33 | config.assets.digest = true
34 |
35 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
36 |
37 | # Specifies the header that your server uses for sending files.
38 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
39 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
40 |
41 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
42 | # config.force_ssl = true
43 |
44 | # Set to :debug to see everything in the log.
45 | config.log_level = :info
46 |
47 | # Prepend all log lines with the following tags.
48 | # config.log_tags = [ :subdomain, :uuid ]
49 |
50 | # Use a different logger for distributed setups.
51 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
52 |
53 | # Use a different cache store in production.
54 | # config.cache_store = :mem_cache_store
55 |
56 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
57 | # config.action_controller.asset_host = "http://assets.example.com"
58 |
59 | # Ignore bad email addresses and do not raise email delivery errors.
60 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
61 | # config.action_mailer.raise_delivery_errors = false
62 |
63 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
64 | # the I18n.default_locale when a translation cannot be found).
65 | config.i18n.fallbacks = true
66 |
67 | # Send deprecation notices to registered listeners.
68 | config.active_support.deprecation = :notify
69 |
70 | # Disable automatic flushing of the log to improve performance.
71 | # config.autoflush_log = false
72 |
73 | # Use default logging formatter so that PID and timestamp are not suppressed.
74 | config.log_formatter = ::Logger::Formatter.new
75 |
76 | # Do not dump schema after migrations.
77 | config.active_record.dump_schema_after_migration = false
78 | end
79 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/environments/test.rb:
--------------------------------------------------------------------------------
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
40 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/initializers/assets.rb:
--------------------------------------------------------------------------------
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 )
9 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
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!
8 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.action_dispatch.cookies_serializer = :json
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
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]
5 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
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
17 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
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
5 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.session_store :cookie_store, key: '_dummy_session'
4 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
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
15 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/locales/en.yml:
--------------------------------------------------------------------------------
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"
24 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/routes.rb:
--------------------------------------------------------------------------------
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
57 |
--------------------------------------------------------------------------------
/spec/dummy_engine/test/dummy/config/secrets.yml:
--------------------------------------------------------------------------------
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"] %>
23 |
--------------------------------------------------------------------------------
/spec/examples/connection_adapter_examples.rb:
--------------------------------------------------------------------------------
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
43 |
--------------------------------------------------------------------------------
/spec/examples/generic_adapter_custom_configuration_example.rb:
--------------------------------------------------------------------------------
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
96 |
--------------------------------------------------------------------------------
/spec/examples/generic_adapter_examples.rb:
--------------------------------------------------------------------------------
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
164 |
--------------------------------------------------------------------------------
/spec/examples/schema_adapter_examples.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | shared_examples_for "a schema based apartment adapter" do
4 | include Apartment::Spec::AdapterRequirements
5 |
6 | let(:schema1){ db1 }
7 | let(:schema2){ db2 }
8 | let(:public_schema){ default_tenant }
9 |
10 | describe "#init" do
11 |
12 | before do
13 | Apartment.configure do |config|
14 | config.excluded_models = ["Company"]
15 | end
16 | end
17 |
18 | after do
19 | # Apartment::Tenant.init creates per model connection.
20 | # Remove the connection after testing not to unintentionally keep the connection across tests.
21 | Apartment.excluded_models.each do |excluded_model|
22 | excluded_model.constantize.remove_connection
23 | end
24 | end
25 |
26 | it "should process model exclusions" do
27 | Apartment::Tenant.init
28 |
29 | expect(Company.table_name).to eq("public.companies")
30 | end
31 |
32 | context "with a default_schema", :default_schema => true do
33 |
34 | it "should set the proper table_name on excluded_models" do
35 | Apartment::Tenant.init
36 |
37 | expect(Company.table_name).to eq("#{default_schema}.companies")
38 | end
39 |
40 | it 'sets the search_path correctly' do
41 | Apartment::Tenant.init
42 |
43 | expect(User.connection.schema_search_path).to match(%r|#{default_schema}|)
44 | end
45 | end
46 |
47 | context "persistent_schemas", :persistent_schemas => true do
48 | it "sets the persistent schemas in the schema_search_path" do
49 | Apartment::Tenant.init
50 | expect(connection.schema_search_path).to end_with persistent_schemas.map { |schema| %{"#{schema}"} }.join(', ')
51 | end
52 | end
53 | end
54 |
55 | #
56 | # Creates happen already in our before_filter
57 | #
58 | describe "#create" do
59 |
60 | it "should load schema.rb to new schema" do
61 | connection.schema_search_path = schema1
62 | expect(connection.tables).to include('companies')
63 | end
64 |
65 | it "should yield to block if passed and reset" do
66 | subject.drop(schema2) # so we don't get errors on creation
67 |
68 | @count = 0 # set our variable so its visible in and outside of blocks
69 |
70 | subject.create(schema2) do
71 | @count = User.count
72 | expect(connection.schema_search_path).to start_with %{"#{schema2}"}
73 | User.create
74 | end
75 |
76 | expect(connection.schema_search_path).not_to start_with %{"#{schema2}"}
77 |
78 | subject.switch(schema2){ expect(User.count).to eq(@count + 1) }
79 | end
80 |
81 | context "numeric database names" do
82 | let(:db){ 1234 }
83 | it "should allow them" do
84 | expect {
85 | subject.create(db)
86 | }.to_not raise_error
87 | expect(tenant_names).to include(db.to_s)
88 | end
89 |
90 | after{ subject.drop(db) }
91 | end
92 |
93 | end
94 |
95 | describe "#drop" do
96 | it "should raise an error for unknown database" do
97 | expect {
98 | subject.drop "unknown_database"
99 | }.to raise_error(Apartment::TenantNotFound)
100 | end
101 |
102 | context "numeric database names" do
103 | let(:db){ 1234 }
104 |
105 | it "should be able to drop them" do
106 | subject.create(db)
107 | expect {
108 | subject.drop(db)
109 | }.to_not raise_error
110 | expect(tenant_names).not_to include(db.to_s)
111 | end
112 |
113 | after { subject.drop(db) rescue nil }
114 | end
115 | end
116 |
117 | describe "#switch" do
118 | it "connects and resets" do
119 | subject.switch(schema1) do
120 | expect(connection.schema_search_path).to start_with %{"#{schema1}"}
121 | end
122 |
123 | expect(connection.schema_search_path).to start_with %{"#{public_schema}"}
124 | end
125 | end
126 |
127 | describe "#reset" do
128 | it "should reset connection" do
129 | subject.switch!(schema1)
130 | subject.reset
131 | expect(connection.schema_search_path).to start_with %{"#{public_schema}"}
132 | end
133 |
134 | context "with default_schema", :default_schema => true do
135 | it "should reset to the default schema" do
136 | subject.switch!(schema1)
137 | subject.reset
138 | expect(connection.schema_search_path).to start_with %{"#{default_schema}"}
139 | end
140 | end
141 |
142 | context "persistent_schemas", :persistent_schemas => true do
143 | before do
144 | subject.switch!(schema1)
145 | subject.reset
146 | end
147 |
148 | it "maintains the persistent schemas in the schema_search_path" do
149 | expect(connection.schema_search_path).to end_with persistent_schemas.map { |schema| %{"#{schema}"} }.join(', ')
150 | end
151 |
152 | context "with default_schema", :default_schema => true do
153 | it "prioritizes the switched schema to front of schema_search_path" do
154 | subject.reset # need to re-call this as the default_schema wasn't set at the time that the above reset ran
155 | expect(connection.schema_search_path).to start_with %{"#{default_schema}"}
156 | end
157 | end
158 | end
159 | end
160 |
161 | describe "#switch!" do
162 | it "should connect to new schema" do
163 | subject.switch!(schema1)
164 | expect(connection.schema_search_path).to start_with %{"#{schema1}"}
165 | end
166 |
167 | it "should reset connection if database is nil" do
168 | subject.switch!
169 | expect(connection.schema_search_path).to eq(%{"#{public_schema}"})
170 | end
171 |
172 | it "should raise an error if schema is invalid" do
173 | expect {
174 | subject.switch! 'unknown_schema'
175 | }.to raise_error(Apartment::TenantNotFound)
176 | end
177 |
178 | context "numeric databases" do
179 | let(:db){ 1234 }
180 |
181 | it "should connect to them" do
182 | subject.create(db)
183 | expect {
184 | subject.switch!(db)
185 | }.to_not raise_error
186 |
187 | expect(connection.schema_search_path).to start_with %{"#{db.to_s}"}
188 | end
189 |
190 | after{ subject.drop(db) }
191 | end
192 |
193 | describe "with default_schema specified", :default_schema => true do
194 | before do
195 | subject.switch!(schema1)
196 | end
197 |
198 | it "should switch out the default schema rather than public" do
199 | expect(connection.schema_search_path).not_to include default_schema
200 | end
201 |
202 | it "should still switch to the switched schema" do
203 | expect(connection.schema_search_path).to start_with %{"#{schema1}"}
204 | end
205 | end
206 |
207 | context "persistent_schemas", :persistent_schemas => true do
208 |
209 | before{ subject.switch!(schema1) }
210 |
211 | it "maintains the persistent schemas in the schema_search_path" do
212 | expect(connection.schema_search_path).to end_with persistent_schemas.map { |schema| %{"#{schema}"} }.join(', ')
213 | end
214 |
215 | it "prioritizes the switched schema to front of schema_search_path" do
216 | expect(connection.schema_search_path).to start_with %{"#{schema1}"}
217 | end
218 | end
219 | end
220 |
221 | describe "#current" do
222 | it "should return the current schema name" do
223 | subject.switch!(schema1)
224 | expect(subject.current).to eq(schema1)
225 | end
226 |
227 | context "persistent_schemas", :persistent_schemas => true do
228 | it "should exlude persistent_schemas" do
229 | subject.switch!(schema1)
230 | expect(subject.current).to eq(schema1)
231 | end
232 | end
233 | end
234 | end
235 |
--------------------------------------------------------------------------------
/spec/integration/apartment_rake_integration_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'rake'
3 |
4 | describe "apartment rake tasks", database: :postgresql do
5 |
6 | before do
7 | @rake = Rake::Application.new
8 | Rake.application = @rake
9 | Dummy::Application.load_tasks
10 |
11 | # rails tasks running F up the schema...
12 | Rake::Task.define_task('db:migrate')
13 | Rake::Task.define_task('db:seed')
14 | Rake::Task.define_task('db:rollback')
15 | Rake::Task.define_task('db:migrate:up')
16 | Rake::Task.define_task('db:migrate:down')
17 | Rake::Task.define_task('db:migrate:redo')
18 |
19 | Apartment.configure do |config|
20 | config.use_schemas = true
21 | config.excluded_models = ["Company"]
22 | config.tenant_names = lambda{ Company.pluck(:database) }
23 | end
24 | Apartment::Tenant.reload!(config)
25 |
26 | # fix up table name of shared/excluded models
27 | Company.table_name = 'public.companies'
28 | end
29 |
30 | after { Rake.application = nil }
31 |
32 | context "with x number of databases" do
33 |
34 | let(:x){ 1 + rand(5) } # random number of dbs to create
35 | let(:db_names){ x.times.map{ Apartment::Test.next_db } }
36 | let!(:company_count){ db_names.length }
37 |
38 | before do
39 | db_names.collect do |db_name|
40 | Apartment::Tenant.create(db_name)
41 | Company.create :database => db_name
42 | end
43 | end
44 |
45 | after do
46 | db_names.each{ |db| Apartment::Tenant.drop(db) }
47 | Company.delete_all
48 | end
49 |
50 | context "with ActiveRecord below 5.2.0" do
51 | before do
52 | allow(ActiveRecord::Migrator).to receive(:migrations_paths) { %w(spec/dummy/db/migrate) }
53 | allow(Apartment::Migrator).to receive(:activerecord_below_5_2?) { true }
54 | end
55 |
56 | describe "#migrate" do
57 | it "should migrate all databases" do
58 | expect(ActiveRecord::Migrator).to receive(:migrate).exactly(company_count).times
59 |
60 | @rake['apartment:migrate'].invoke
61 | end
62 | end
63 |
64 | describe "#rollback" do
65 | it "should rollback all dbs" do
66 | expect(ActiveRecord::Migrator).to receive(:rollback).exactly(company_count).times
67 |
68 | @rake['apartment:rollback'].invoke
69 | end
70 | end
71 | end
72 |
73 | context "with ActiveRecord above or equal to 5.2.0" do
74 | let(:migration_context_double) { double(:migration_context) }
75 |
76 | before do
77 | allow(Apartment::Migrator).to receive(:activerecord_below_5_2?) { false }
78 | end
79 |
80 | describe "#migrate" do
81 | it "should migrate all databases" do
82 | allow(ActiveRecord::Base.connection).to receive(:migration_context) { migration_context_double }
83 | expect(migration_context_double).to receive(:migrate).exactly(company_count).times
84 |
85 | @rake['apartment:migrate'].invoke
86 | end
87 | end
88 |
89 | describe "#rollback" do
90 | it "should rollback all dbs" do
91 | allow(ActiveRecord::Base.connection).to receive(:migration_context) { migration_context_double }
92 | expect(migration_context_double).to receive(:rollback).exactly(company_count).times
93 |
94 | @rake['apartment:rollback'].invoke
95 | end
96 | end
97 | end
98 |
99 | describe "apartment:seed" do
100 | it "should seed all databases" do
101 | expect(Apartment::Tenant).to receive(:seed).exactly(company_count).times
102 |
103 | @rake['apartment:seed'].invoke
104 | end
105 | end
106 | end
107 | end
108 |
--------------------------------------------------------------------------------
/spec/integration/query_caching_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe 'query caching' do
4 | describe 'when use_schemas = true' do
5 | let(:db_names) { [db1, db2] }
6 |
7 | before do
8 | Apartment.configure do |config|
9 | config.excluded_models = ["Company"]
10 | config.tenant_names = lambda{ Company.pluck(:database) }
11 | config.use_schemas = true
12 | end
13 |
14 | Apartment::Tenant.reload!(config)
15 |
16 | db_names.each do |db_name|
17 | Apartment::Tenant.create(db_name)
18 | Company.create database: db_name
19 | end
20 | end
21 |
22 | after do
23 | db_names.each{ |db| Apartment::Tenant.drop(db) }
24 | Apartment::Tenant.reset
25 | Company.delete_all
26 | end
27 |
28 | it 'clears the ActiveRecord::QueryCache after switching databases' do
29 | db_names.each do |db_name|
30 | Apartment::Tenant.switch! db_name
31 | User.create! name: db_name
32 | end
33 |
34 | ActiveRecord::Base.connection.enable_query_cache!
35 |
36 | Apartment::Tenant.switch! db_names.first
37 | expect(User.find_by_name(db_names.first).name).to eq(db_names.first)
38 |
39 | Apartment::Tenant.switch! db_names.last
40 | expect(User.find_by_name(db_names.first)).to be_nil
41 | end
42 | end
43 |
44 | describe 'when use_schemas = false' do
45 | let(:db_name) { db1 }
46 |
47 | before do
48 | Apartment.configure do |config|
49 | config.excluded_models = ["Company"]
50 | config.tenant_names = lambda{ Company.pluck(:database) }
51 | config.use_schemas = false
52 | end
53 |
54 | Apartment::Tenant.reload!(config)
55 |
56 | Apartment::Tenant.create(db_name)
57 | Company.create database: db_name
58 | end
59 |
60 | after do
61 | # Avoid cannot drop the currently open database. Maybe there is a better way to handle this.
62 | Apartment::Tenant.switch! 'template1'
63 |
64 | Apartment::Tenant.drop(db_name)
65 | Apartment::Tenant.reset
66 | Company.delete_all
67 | end
68 |
69 | it "configuration value is kept after switching databases" do
70 | ActiveRecord::Base.connection.enable_query_cache!
71 |
72 | Apartment::Tenant.switch! db_name
73 | expect(Apartment.connection.query_cache_enabled).to be true
74 |
75 | ActiveRecord::Base.connection.disable_query_cache!
76 |
77 | Apartment::Tenant.switch! db_name
78 | expect(Apartment.connection.query_cache_enabled).to be false
79 | end
80 | end
81 | end
82 |
--------------------------------------------------------------------------------
/spec/integration/use_within_an_engine_spec.rb:
--------------------------------------------------------------------------------
1 | describe 'using apartment within an engine' do
2 |
3 | before do
4 | engine_path = Pathname.new(File.expand_path('../../dummy_engine', __FILE__))
5 | require engine_path.join('test/dummy/config/application')
6 | @rake = Rake::Application.new
7 | Rake.application = @rake
8 | stub_const 'APP_RAKEFILE', engine_path.join('test/dummy/Rakefile')
9 | load 'rails/tasks/engine.rake'
10 | end
11 |
12 | it 'sucessfully runs rake db:migrate in the engine root' do
13 | expect{ Rake::Task['db:migrate'].invoke }.to_not raise_error
14 | end
15 |
16 | it 'sucessfully runs rake app:db:migrate in the engine root' do
17 | expect{ Rake::Task['app:db:migrate'].invoke }.to_not raise_error
18 | end
19 |
20 | context 'when Apartment.db_migrate_tenants is false' do
21 | it 'should not enhance tasks' do
22 | Apartment.db_migrate_tenants = false
23 | expect(Apartment::RakeTaskEnhancer).to_not receive(:enhance_task).with('db:migrate')
24 | Rake::Task['db:migrate'].invoke
25 | end
26 | end
27 |
28 | end
29 |
--------------------------------------------------------------------------------
/spec/schemas/v1.rb:
--------------------------------------------------------------------------------
1 | # encoding: UTF-8
2 | # This file is auto-generated from the current state of the database. Instead
3 | # of editing this file, please use the migrations feature of Active Record to
4 | # incrementally modify your database, and then regenerate this schema definition.
5 | #
6 | # Note that this schema.rb definition is the authoritative source for your
7 | # database schema. If you need to create the application database on another
8 | # system, you should be using db:schema:load, not running all the migrations
9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 | # you'll amass, the slower it'll run and the greater likelihood for issues).
11 | #
12 | # It's strongly recommended to check this file into your version control system.
13 |
14 | ActiveRecord::Schema.define(:version => 0) do
15 |
16 | end
17 |
--------------------------------------------------------------------------------
/spec/schemas/v2.rb:
--------------------------------------------------------------------------------
1 | # encoding: UTF-8
2 | # This file is auto-generated from the current state of the database. Instead
3 | # of editing this file, please use the migrations feature of Active Record to
4 | # incrementally modify your database, and then regenerate this schema definition.
5 | #
6 | # Note that this schema.rb definition is the authoritative source for your
7 | # database schema. If you need to create the application database on another
8 | # system, you should be using db:schema:load, not running all the migrations
9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 | # you'll amass, the slower it'll run and the greater likelihood for issues).
11 | #
12 | # It's strongly recommended to check this file into your version control system.
13 |
14 | ActiveRecord::Schema.define(:version => 20110613152810) do
15 |
16 | create_table "companies", :force => true do |t|
17 | t.boolean "dummy"
18 | t.string "database"
19 | end
20 |
21 | create_table "delayed_jobs", :force => true do |t|
22 | t.integer "priority", :default => 0
23 | t.integer "attempts", :default => 0
24 | t.text "handler"
25 | t.text "last_error"
26 | t.datetime "run_at"
27 | t.datetime "locked_at"
28 | t.datetime "failed_at"
29 | t.string "locked_by"
30 | t.datetime "created_at"
31 | t.datetime "updated_at"
32 | t.string "queue"
33 | end
34 |
35 | add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority"
36 |
37 | create_table "users", :force => true do |t|
38 | t.string "name"
39 | t.datetime "birthdate"
40 | t.string "sex"
41 | end
42 |
43 | end
44 |
--------------------------------------------------------------------------------
/spec/schemas/v3.rb:
--------------------------------------------------------------------------------
1 | # encoding: UTF-8
2 | # This file is auto-generated from the current state of the database. Instead
3 | # of editing this file, please use the migrations feature of Active Record to
4 | # incrementally modify your database, and then regenerate this schema definition.
5 | #
6 | # Note that this schema.rb definition is the authoritative source for your
7 | # database schema. If you need to create the application database on another
8 | # system, you should be using db:schema:load, not running all the migrations
9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 | # you'll amass, the slower it'll run and the greater likelihood for issues).
11 | #
12 | # It's strongly recommended to check this file into your version control system.
13 |
14 | ActiveRecord::Schema.define(:version => 20111202022214) do
15 |
16 | create_table "books", :force => true do |t|
17 | t.string "name"
18 | t.integer "pages"
19 | t.datetime "published"
20 | end
21 |
22 | create_table "companies", :force => true do |t|
23 | t.boolean "dummy"
24 | t.string "database"
25 | end
26 |
27 | create_table "delayed_jobs", :force => true do |t|
28 | t.integer "priority", :default => 0
29 | t.integer "attempts", :default => 0
30 | t.text "handler"
31 | t.text "last_error"
32 | t.datetime "run_at"
33 | t.datetime "locked_at"
34 | t.datetime "failed_at"
35 | t.string "locked_by"
36 | t.datetime "created_at"
37 | t.datetime "updated_at"
38 | t.string "queue"
39 | end
40 |
41 | add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority"
42 |
43 | create_table "users", :force => true do |t|
44 | t.string "name"
45 | t.datetime "birthdate"
46 | t.string "sex"
47 | end
48 |
49 | end
50 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | $LOAD_PATH.unshift(File.dirname(__FILE__))
2 |
3 | # Configure Rails Environment
4 | ENV["RAILS_ENV"] = "test"
5 |
6 | require File.expand_path("../dummy/config/environment.rb", __FILE__)
7 |
8 | # Loading dummy applications affects table_name of each excluded models
9 | # defined in `spec/dummy/config/initializers/apartment.rb`.
10 | # To make them pristine, we need to execute below lines.
11 | Apartment.excluded_models.each do |model|
12 | klass = model.constantize
13 |
14 | Apartment.connection_class.remove_connection(klass)
15 | klass.clear_all_connections!
16 | klass.reset_table_name
17 | end
18 |
19 | require "rspec/rails"
20 | require 'capybara/rspec'
21 | require 'capybara/rails'
22 |
23 | begin
24 | require 'pry'
25 | silence_warnings{ IRB = Pry }
26 | rescue LoadError
27 | end
28 |
29 | ActionMailer::Base.delivery_method = :test
30 | ActionMailer::Base.perform_deliveries = true
31 | ActionMailer::Base.default_url_options[:host] = "test.com"
32 |
33 | Rails.backtrace_cleaner.remove_silencers!
34 |
35 | # Load support files
36 | Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
37 |
38 | RSpec.configure do |config|
39 |
40 | config.include RSpec::Integration::CapybaraSessions, type: :request
41 | config.include Apartment::Spec::Setup
42 |
43 | # Somewhat brutal hack so that rails 4 postgres extensions don't modify this file
44 | config.after(:all) do
45 | `git checkout -- spec/dummy/db/schema.rb`
46 | end
47 |
48 | # rspec-rails 3 will no longer automatically infer an example group's spec type
49 | # from the file location. You can explicitly opt-in to the feature using this
50 | # config option.
51 | # To explicitly tag specs without using automatic inference, set the `:type`
52 | # metadata manually:
53 | #
54 | # describe ThingsController, :type => :controller do
55 | # # Equivalent to being in spec/controllers
56 | # end
57 | config.infer_spec_type_from_file_location!
58 | end
59 |
60 | # Load shared examples, must happen after configure for RSpec 3
61 | Dir["#{File.dirname(__FILE__)}/examples/**/*.rb"].each { |f| require f }
62 |
--------------------------------------------------------------------------------
/spec/support/apartment_helpers.rb:
--------------------------------------------------------------------------------
1 | module Apartment
2 | module Test
3 |
4 | extend self
5 |
6 | def reset
7 | Apartment.excluded_models = nil
8 | Apartment.use_schemas = nil
9 | Apartment.seed_after_create = nil
10 | Apartment.default_schema = nil
11 | end
12 |
13 | def next_db
14 | @x ||= 0
15 | "db%d" % @x += 1
16 | end
17 |
18 | def drop_schema(schema)
19 | ActiveRecord::Base.connection.execute("DROP SCHEMA IF EXISTS #{schema} CASCADE") rescue true
20 | end
21 |
22 | # Use this if you don't want to import schema.rb etc... but need the postgres schema to exist
23 | # basically for speed purposes
24 | def create_schema(schema)
25 | ActiveRecord::Base.connection.execute("CREATE SCHEMA #{schema}")
26 | end
27 |
28 | def load_schema(version = 3)
29 | file = File.expand_path("../../schemas/v#{version}.rb", __FILE__)
30 |
31 | silence_warnings{ load(file) }
32 | end
33 |
34 | def migrate
35 | ActiveRecord::Migrator.migrate(Rails.root + ActiveRecord::Migrator.migrations_path)
36 | end
37 |
38 | def rollback
39 | ActiveRecord::Migrator.rollback(Rails.root + ActiveRecord::Migrator.migrations_path)
40 | end
41 |
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/spec/support/capybara_sessions.rb:
--------------------------------------------------------------------------------
1 | module RSpec
2 | module Integration
3 | module CapybaraSessions
4 |
5 | def in_new_session(&block)
6 | yield new_session
7 | end
8 |
9 | def new_session
10 | Capybara::Session.new(Capybara.current_driver, Capybara.app)
11 | end
12 |
13 | end
14 | end
15 | end
--------------------------------------------------------------------------------
/spec/support/config.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 |
3 | module Apartment
4 | module Test
5 |
6 | def self.config
7 | @config ||= YAML.load(ERB.new(IO.read('spec/config/database.yml')).result)
8 | end
9 | end
10 | end
--------------------------------------------------------------------------------
/spec/support/contexts.rb:
--------------------------------------------------------------------------------
1 | # Some shared contexts for specs
2 |
3 | shared_context "with default schema", :default_schema => true do
4 | let(:default_schema){ Apartment::Test.next_db }
5 |
6 | before do
7 | Apartment::Test.create_schema(default_schema)
8 | Apartment.default_schema = default_schema
9 | end
10 |
11 | after do
12 | # resetting default_schema so we can drop and any further resets won't try to access droppped schema
13 | Apartment.default_schema = nil
14 | Apartment::Test.drop_schema(default_schema)
15 | end
16 | end
17 |
18 | # Some default setup for elevator specs
19 | shared_context "elevators", elevator: true do
20 | let(:company1) { mock_model(Company, database: db1).as_null_object }
21 | let(:company2) { mock_model(Company, database: db2).as_null_object }
22 |
23 | let(:api) { Apartment::Tenant }
24 |
25 | before do
26 | Apartment.reset # reset all config
27 | Apartment.seed_after_create = false
28 | Apartment.use_schemas = true
29 | api.reload!(config)
30 | api.create(db1)
31 | api.create(db2)
32 | end
33 |
34 | after do
35 | api.drop(db1)
36 | api.drop(db2)
37 | end
38 | end
39 |
40 | shared_context "persistent_schemas", :persistent_schemas => true do
41 | let(:persistent_schemas){ ['hstore', 'postgis'] }
42 |
43 | before do
44 | persistent_schemas.map{|schema| subject.create(schema) }
45 | Apartment.persistent_schemas = persistent_schemas
46 | end
47 |
48 | after do
49 | Apartment.persistent_schemas = []
50 | persistent_schemas.map{|schema| subject.drop(schema) }
51 | end
52 | end
--------------------------------------------------------------------------------
/spec/support/requirements.rb:
--------------------------------------------------------------------------------
1 | module Apartment
2 | module Spec
3 |
4 | #
5 | # Define the interface methods required to
6 | # use an adapter shared example
7 | #
8 | #
9 | module AdapterRequirements
10 | extend ActiveSupport::Concern
11 |
12 | included do
13 | before do
14 | subject.create(db1)
15 | subject.create(db2)
16 | end
17 |
18 | after do
19 | # Reset before dropping (can't drop a db you're connected to)
20 | subject.reset
21 |
22 | # sometimes we manually drop these schemas in testing, don't care if we can't drop, hence rescue
23 | subject.drop(db1) rescue true
24 | subject.drop(db2) rescue true
25 | end
26 | end
27 |
28 | %w{subject tenant_names default_tenant}.each do |method|
29 | define_method method do
30 | raise "You must define a `#{method}` method in your host group"
31 | end unless defined?(method)
32 | end
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/spec/support/setup.rb:
--------------------------------------------------------------------------------
1 | module Apartment
2 | module Spec
3 | module Setup
4 |
5 | def self.included(base)
6 | base.instance_eval do
7 | let(:db1){ Apartment::Test.next_db }
8 | let(:db2){ Apartment::Test.next_db }
9 | let(:connection){ ActiveRecord::Base.connection }
10 |
11 | # This around ensures that we run these hooks before and after
12 | # any before/after hooks defined in individual tests
13 | # Otherwise these actually get run after test defined hooks
14 | around(:each) do |example|
15 |
16 | def config
17 | db = RSpec.current_example.metadata.fetch(:database, :postgresql)
18 |
19 | Apartment::Test.config['connections'][db.to_s].symbolize_keys
20 | end
21 |
22 | # before
23 | Apartment::Tenant.reload!(config)
24 | ActiveRecord::Base.establish_connection config
25 |
26 | example.run
27 |
28 | # after
29 | Rails.configuration.database_configuration = {}
30 | ActiveRecord::Base.clear_all_connections!
31 |
32 | Apartment.excluded_models.each do |model|
33 | klass = model.constantize
34 |
35 | Apartment.connection_class.remove_connection(klass)
36 | klass.clear_all_connections!
37 | klass.reset_table_name
38 | end
39 | Apartment.reset
40 | Apartment::Tenant.reload!
41 | end
42 | end
43 | end
44 | end
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/spec/tasks/apartment_rake_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'rake'
3 | require 'apartment/migrator'
4 | require 'apartment/tenant'
5 |
6 | describe "apartment rake tasks" do
7 |
8 | before do
9 | @rake = Rake::Application.new
10 | Rake.application = @rake
11 | load 'tasks/apartment.rake'
12 | # stub out rails tasks
13 | Rake::Task.define_task('db:migrate')
14 | Rake::Task.define_task('db:seed')
15 | Rake::Task.define_task('db:rollback')
16 | Rake::Task.define_task('db:migrate:up')
17 | Rake::Task.define_task('db:migrate:down')
18 | Rake::Task.define_task('db:migrate:redo')
19 | end
20 |
21 | after do
22 | Rake.application = nil
23 | ENV['VERSION'] = nil # linux users reported env variable carrying on between tests
24 | end
25 |
26 | after(:all) do
27 | Apartment::Test.load_schema
28 | end
29 |
30 | let(:version){ '1234' }
31 |
32 | context 'database migration' do
33 |
34 | let(:tenant_names){ 3.times.map{ Apartment::Test.next_db } }
35 | let(:tenant_count){ tenant_names.length }
36 |
37 | before do
38 | allow(Apartment).to receive(:tenant_names).and_return tenant_names
39 | end
40 |
41 | describe "apartment:migrate" do
42 | before do
43 | allow(ActiveRecord::Migrator).to receive(:migrate) # don't care about this
44 | end
45 |
46 | it "should migrate public and all multi-tenant dbs" do
47 | expect(Apartment::Migrator).to receive(:migrate).exactly(tenant_count).times
48 | @rake['apartment:migrate'].invoke
49 | end
50 | end
51 |
52 | describe "apartment:migrate:up" do
53 |
54 | context "without a version" do
55 | before do
56 | ENV['VERSION'] = nil
57 | end
58 |
59 | it "requires a version to migrate to" do
60 | expect{
61 | @rake['apartment:migrate:up'].invoke
62 | }.to raise_error("VERSION is required")
63 | end
64 | end
65 |
66 | context "with version" do
67 |
68 | before do
69 | ENV['VERSION'] = version
70 | end
71 |
72 | it "migrates up to a specific version" do
73 | expect(Apartment::Migrator).to receive(:run).with(:up, anything, version.to_i).exactly(tenant_count).times
74 | @rake['apartment:migrate:up'].invoke
75 | end
76 | end
77 | end
78 |
79 | describe "apartment:migrate:down" do
80 |
81 | context "without a version" do
82 | before do
83 | ENV['VERSION'] = nil
84 | end
85 |
86 | it "requires a version to migrate to" do
87 | expect{
88 | @rake['apartment:migrate:down'].invoke
89 | }.to raise_error("VERSION is required")
90 | end
91 | end
92 |
93 | context "with version" do
94 |
95 | before do
96 | ENV['VERSION'] = version
97 | end
98 |
99 | it "migrates up to a specific version" do
100 | expect(Apartment::Migrator).to receive(:run).with(:down, anything, version.to_i).exactly(tenant_count).times
101 | @rake['apartment:migrate:down'].invoke
102 | end
103 | end
104 | end
105 |
106 | describe "apartment:rollback" do
107 | let(:step){ '3' }
108 |
109 | it "should rollback dbs" do
110 | expect(Apartment::Migrator).to receive(:rollback).exactly(tenant_count).times
111 | @rake['apartment:rollback'].invoke
112 | end
113 |
114 | it "should rollback dbs STEP amt" do
115 | expect(Apartment::Migrator).to receive(:rollback).with(anything, step.to_i).exactly(tenant_count).times
116 | ENV['STEP'] = step
117 | @rake['apartment:rollback'].invoke
118 | end
119 | end
120 |
121 | describe "apartment:drop" do
122 | it "should migrate public and all multi-tenant dbs" do
123 | expect(Apartment::Tenant).to receive(:drop).exactly(tenant_count).times
124 | @rake['apartment:drop'].invoke
125 | end
126 | end
127 |
128 | end
129 | end
130 |
--------------------------------------------------------------------------------
/spec/tenant_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Apartment::Tenant do
4 | context "using mysql", database: :mysql do
5 |
6 | before { subject.reload!(config) }
7 |
8 | describe "#adapter" do
9 | it "should load mysql adapter" do
10 | subject.adapter
11 | expect(Apartment::Adapters::Mysql2Adapter).to be_a(Class)
12 | end
13 | end
14 |
15 | # TODO this doesn't belong here, but there aren't integration tests currently for mysql
16 | # where to put???
17 | describe "exception recovery", :type => :request do
18 | before do
19 | subject.create db1
20 | end
21 | after{ subject.drop db1 }
22 |
23 | # it "should recover from incorrect database" do
24 | # session = Capybara::Session.new(:rack_test, Capybara.app)
25 | # session.visit("http://#{db1}.com")
26 | # expect {
27 | # session.visit("http://this-database-should-not-exist.com")
28 | # }.to raise_error
29 | # session.visit("http://#{db1}.com")
30 | # end
31 | end
32 |
33 | # TODO re-organize these tests
34 | context "with prefix and schemas" do
35 | describe "#create" do
36 | before do
37 | Apartment.configure do |config|
38 | config.prepend_environment = true
39 | config.use_schemas = true
40 | end
41 |
42 | subject.reload!(config)
43 | end
44 |
45 | after { subject.drop "db_with_prefix" rescue nil }
46 |
47 | it "should create a new database" do
48 | subject.create "db_with_prefix"
49 | end
50 | end
51 | end
52 | end
53 |
54 | context "using postgresql", database: :postgresql do
55 | before do
56 | Apartment.use_schemas = true
57 | subject.reload!(config)
58 | end
59 |
60 | describe "#adapter" do
61 | it "should load postgresql adapter" do
62 | expect(subject.adapter).to be_a(Apartment::Adapters::PostgresqlSchemaAdapter)
63 | end
64 |
65 | it "raises exception with invalid adapter specified" do
66 | subject.reload!(config.merge(adapter: 'unknown'))
67 |
68 | expect {
69 | Apartment::Tenant.adapter
70 | }.to raise_error(RuntimeError)
71 | end
72 |
73 | context "threadsafety" do
74 | before { subject.create db1 }
75 | after { subject.drop db1 }
76 |
77 | it 'has a threadsafe adapter' do
78 | subject.switch!(db1)
79 | thread = Thread.new { expect(subject.current).to eq(Apartment.default_tenant) }
80 | thread.join
81 | expect(subject.current).to eq(db1)
82 | end
83 | end
84 | end
85 |
86 | # TODO above spec are also with use_schemas=true
87 | context "with schemas" do
88 | before do
89 | Apartment.configure do |config|
90 | config.excluded_models = []
91 | config.use_schemas = true
92 | config.seed_after_create = true
93 | end
94 | subject.create db1
95 | end
96 |
97 | after{ subject.drop db1 }
98 |
99 | describe "#create" do
100 | it "should seed data" do
101 | subject.switch! db1
102 | expect(User.count).to be > 0
103 | end
104 | end
105 |
106 | describe "#switch!" do
107 |
108 | let(:x){ rand(3) }
109 |
110 | context "creating models" do
111 |
112 | before{ subject.create db2 }
113 | after{ subject.drop db2 }
114 |
115 | it "should create a model instance in the current schema" do
116 | subject.switch! db2
117 | db2_count = User.count + x.times{ User.create }
118 |
119 | subject.switch! db1
120 | db_count = User.count + x.times{ User.create }
121 |
122 | subject.switch! db2
123 | expect(User.count).to eq(db2_count)
124 |
125 | subject.switch! db1
126 | expect(User.count).to eq(db_count)
127 | end
128 | end
129 |
130 | context "with excluded models" do
131 |
132 | before do
133 | Apartment.configure do |config|
134 | config.excluded_models = ["Company"]
135 | end
136 | subject.init
137 | end
138 |
139 | after do
140 | # Apartment::Tenant.init creates per model connection.
141 | # Remove the connection after testing not to unintentionally keep the connection across tests.
142 | Apartment.excluded_models.each do |excluded_model|
143 | excluded_model.constantize.remove_connection
144 | end
145 | end
146 |
147 | it "should create excluded models in public schema" do
148 | subject.reset # ensure we're on public schema
149 | count = Company.count + x.times{ Company.create }
150 |
151 | subject.switch! db1
152 | x.times{ Company.create }
153 | expect(Company.count).to eq(count + x)
154 | subject.reset
155 | expect(Company.count).to eq(count + x)
156 | end
157 | end
158 | end
159 | end
160 |
161 | context "seed paths" do
162 | before do
163 | Apartment.configure do |config|
164 | config.excluded_models = []
165 | config.use_schemas = true
166 | config.seed_after_create = true
167 | end
168 | end
169 |
170 | after{ subject.drop db1 }
171 |
172 | it 'should seed from default path' do
173 | subject.create db1
174 | subject.switch! db1
175 | expect(User.count).to eq(3)
176 | expect(User.first.name).to eq('Some User 0')
177 | end
178 |
179 | it 'should seed from custom path' do
180 | Apartment.configure do |config|
181 | config.seed_data_file = "#{Rails.root}/db/seeds/import.rb"
182 | end
183 | subject.create db1
184 | subject.switch! db1
185 | expect(User.count).to eq(6)
186 | expect(User.first.name).to eq('Different User 0')
187 | end
188 | end
189 | end
190 | end
191 |
--------------------------------------------------------------------------------
/spec/unit/config_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Apartment do
4 |
5 | describe "#config" do
6 |
7 | let(:excluded_models){ ["Company"] }
8 | let(:seed_data_file_path){ "#{Rails.root}/db/seeds/import.rb" }
9 |
10 | def tenant_names_from_array(names)
11 | names.each_with_object({}) do |tenant, hash|
12 | hash[tenant] = Apartment.connection_config
13 | end.with_indifferent_access
14 | end
15 |
16 | it "should yield the Apartment object" do
17 | Apartment.configure do |config|
18 | config.excluded_models = []
19 | expect(config).to eq(Apartment)
20 | end
21 | end
22 |
23 | it "should set excluded models" do
24 | Apartment.configure do |config|
25 | config.excluded_models = excluded_models
26 | end
27 | expect(Apartment.excluded_models).to eq(excluded_models)
28 | end
29 |
30 | it "should set use_schemas" do
31 | Apartment.configure do |config|
32 | config.excluded_models = []
33 | config.use_schemas = false
34 | end
35 | expect(Apartment.use_schemas).to be false
36 | end
37 |
38 | it "should set seed_data_file" do
39 | Apartment.configure do |config|
40 | config.seed_data_file = seed_data_file_path
41 | end
42 | expect(Apartment.seed_data_file).to eq(seed_data_file_path)
43 | end
44 |
45 | it "should set seed_after_create" do
46 | Apartment.configure do |config|
47 | config.excluded_models = []
48 | config.seed_after_create = true
49 | end
50 | expect(Apartment.seed_after_create).to be true
51 | end
52 |
53 | context "databases" do
54 | let(:users_conf_hash) { { port: 5444 } }
55 |
56 | before do
57 | Apartment.configure do |config|
58 | config.tenant_names = tenant_names
59 | end
60 | end
61 |
62 | context "tenant_names as string array" do
63 | let(:tenant_names) { ['users', 'companies'] }
64 |
65 | it "should return object if it doesnt respond_to call" do
66 | expect(Apartment.tenant_names).to eq(tenant_names_from_array(tenant_names).keys)
67 | end
68 |
69 | it "should set tenants_with_config" do
70 | expect(Apartment.tenants_with_config).to eq(tenant_names_from_array(tenant_names))
71 | end
72 | end
73 |
74 | context "tenant_names as proc returning an array" do
75 | let(:tenant_names) { lambda { ['users', 'companies'] } }
76 |
77 | it "should return object if it doesnt respond_to call" do
78 | expect(Apartment.tenant_names).to eq(tenant_names_from_array(tenant_names.call).keys)
79 | end
80 |
81 | it "should set tenants_with_config" do
82 | expect(Apartment.tenants_with_config).to eq(tenant_names_from_array(tenant_names.call))
83 | end
84 | end
85 |
86 | context "tenant_names as Hash" do
87 | let(:tenant_names) { { users: users_conf_hash }.with_indifferent_access }
88 |
89 | it "should return object if it doesnt respond_to call" do
90 | expect(Apartment.tenant_names).to eq(tenant_names.keys)
91 | end
92 |
93 | it "should set tenants_with_config" do
94 | expect(Apartment.tenants_with_config).to eq(tenant_names)
95 | end
96 | end
97 |
98 | context "tenant_names as proc returning a Hash" do
99 | let(:tenant_names) { lambda { { users: users_conf_hash }.with_indifferent_access } }
100 |
101 | it "should return object if it doesnt respond_to call" do
102 | expect(Apartment.tenant_names).to eq(tenant_names.call.keys)
103 | end
104 |
105 | it "should set tenants_with_config" do
106 | expect(Apartment.tenants_with_config).to eq(tenant_names.call)
107 | end
108 | end
109 | end
110 |
111 | end
112 | end
113 |
--------------------------------------------------------------------------------
/spec/unit/elevators/domain_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'apartment/elevators/domain'
3 |
4 | describe Apartment::Elevators::Domain do
5 |
6 | subject(:elevator){ described_class.new(Proc.new{}) }
7 |
8 | describe "#parse_tenant_name" do
9 | it "parses the host for a domain name" do
10 | request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com')
11 | expect(elevator.parse_tenant_name(request)).to eq('example')
12 | end
13 |
14 | it "ignores a www prefix and domain suffix" do
15 | request = ActionDispatch::Request.new('HTTP_HOST' => 'www.example.bc.ca')
16 | expect(elevator.parse_tenant_name(request)).to eq('example')
17 | end
18 |
19 | it "returns nil if there is no host" do
20 | request = ActionDispatch::Request.new('HTTP_HOST' => '')
21 | expect(elevator.parse_tenant_name(request)).to be_nil
22 | end
23 | end
24 |
25 | describe "#call" do
26 | it "switches to the proper tenant" do
27 | expect(Apartment::Tenant).to receive(:switch).with('example')
28 |
29 | elevator.call('HTTP_HOST' => 'www.example.com')
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/spec/unit/elevators/first_subdomain_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'apartment/elevators/first_subdomain'
3 |
4 | describe Apartment::Elevators::FirstSubdomain do
5 | describe "subdomain" do
6 | subject { described_class.new("test").parse_tenant_name(request) }
7 | let(:request) { double(:request, :host => "#{subdomain}.example.com") }
8 |
9 | context "one subdomain" do
10 | let(:subdomain) { "test" }
11 | it { is_expected.to eq("test") }
12 | end
13 |
14 | context "nested subdomains" do
15 | let(:subdomain) { "test1.test2" }
16 | it { is_expected.to eq("test1") }
17 | end
18 |
19 | context "no subdomain" do
20 | let(:subdomain) { nil }
21 | it { is_expected.to eq(nil) }
22 | end
23 | end
24 | end
--------------------------------------------------------------------------------
/spec/unit/elevators/generic_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'apartment/elevators/generic'
3 |
4 | describe Apartment::Elevators::Generic do
5 |
6 | class MyElevator < described_class
7 | def parse_tenant_name(*)
8 | 'tenant2'
9 | end
10 | end
11 |
12 | subject(:elevator){ described_class.new(Proc.new{}) }
13 |
14 | describe "#call" do
15 | it "calls the processor if given" do
16 | elevator = described_class.new(Proc.new{}, Proc.new{'tenant1'})
17 |
18 | expect(Apartment::Tenant).to receive(:switch).with('tenant1')
19 |
20 | elevator.call('HTTP_HOST' => 'foo.bar.com')
21 | end
22 |
23 | it "raises if parse_tenant_name not implemented" do
24 | expect {
25 | elevator.call('HTTP_HOST' => 'foo.bar.com')
26 | }.to raise_error(RuntimeError)
27 | end
28 |
29 | it "switches to the parsed db_name" do
30 | elevator = MyElevator.new(Proc.new{})
31 |
32 | expect(Apartment::Tenant).to receive(:switch).with('tenant2')
33 |
34 | elevator.call('HTTP_HOST' => 'foo.bar.com')
35 | end
36 |
37 | it "calls the block implementation of `switch`" do
38 | elevator = MyElevator.new(Proc.new{}, Proc.new{'tenant2'})
39 |
40 | expect(Apartment::Tenant).to receive(:switch).with('tenant2').and_yield
41 | elevator.call('HTTP_HOST' => 'foo.bar.com')
42 | end
43 |
44 | it "does not call `switch` if no database given" do
45 | app = Proc.new{}
46 | elevator = MyElevator.new(app, Proc.new{})
47 |
48 | expect(Apartment::Tenant).not_to receive(:switch)
49 | expect(app).to receive :call
50 |
51 | elevator.call('HTTP_HOST' => 'foo.bar.com')
52 | end
53 | end
54 | end
55 |
--------------------------------------------------------------------------------
/spec/unit/elevators/host_hash_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'apartment/elevators/host_hash'
3 |
4 | describe Apartment::Elevators::HostHash do
5 |
6 | subject(:elevator){ Apartment::Elevators::HostHash.new(Proc.new{}, 'example.com' => 'example_tenant') }
7 |
8 | describe "#parse_tenant_name" do
9 | it "parses the host for a domain name" do
10 | request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com')
11 | expect(elevator.parse_tenant_name(request)).to eq('example_tenant')
12 | end
13 |
14 | it "raises TenantNotFound exception if there is no host" do
15 | request = ActionDispatch::Request.new('HTTP_HOST' => '')
16 | expect { elevator.parse_tenant_name(request) }.to raise_error(Apartment::TenantNotFound)
17 | end
18 |
19 | it "raises TenantNotFound exception if there is no database associated to current host" do
20 | request = ActionDispatch::Request.new('HTTP_HOST' => 'example2.com')
21 | expect { elevator.parse_tenant_name(request) }.to raise_error(Apartment::TenantNotFound)
22 | end
23 | end
24 |
25 | describe "#call" do
26 | it "switches to the proper tenant" do
27 | expect(Apartment::Tenant).to receive(:switch).with('example_tenant')
28 |
29 | elevator.call('HTTP_HOST' => 'example.com')
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/spec/unit/elevators/host_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'apartment/elevators/host'
3 |
4 | describe Apartment::Elevators::Host do
5 |
6 | subject(:elevator){ described_class.new(Proc.new{}) }
7 |
8 | describe "#parse_tenant_name" do
9 |
10 | it "should return nil when no host" do
11 | request = ActionDispatch::Request.new('HTTP_HOST' => '')
12 | expect(elevator.parse_tenant_name(request)).to be_nil
13 | end
14 |
15 | context "assuming no ignored_first_subdomains" do
16 | before { allow(described_class).to receive(:ignored_first_subdomains).and_return([]) }
17 |
18 | context "with 3 parts" do
19 | it "should return the whole host" do
20 | request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com')
21 | expect(elevator.parse_tenant_name(request)).to eq('foo.bar.com')
22 | end
23 | end
24 |
25 | context "with 6 parts" do
26 | it "should return the whole host" do
27 | request = ActionDispatch::Request.new('HTTP_HOST' => 'one.two.three.foo.bar.com')
28 | expect(elevator.parse_tenant_name(request)).to eq('one.two.three.foo.bar.com')
29 | end
30 | end
31 | end
32 |
33 | context "assuming ignored_first_subdomains is set" do
34 | before { allow(described_class).to receive(:ignored_first_subdomains).and_return(%w{www foo}) }
35 |
36 | context "with 3 parts" do
37 | it "should return host without www" do
38 | request = ActionDispatch::Request.new('HTTP_HOST' => 'www.bar.com')
39 | expect(elevator.parse_tenant_name(request)).to eq('bar.com')
40 | end
41 |
42 | it "should return host without foo" do
43 | request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com')
44 | expect(elevator.parse_tenant_name(request)).to eq('bar.com')
45 | end
46 | end
47 |
48 | context "with 6 parts" do
49 | it "should return host without www" do
50 | request = ActionDispatch::Request.new('HTTP_HOST' => 'www.one.two.three.foo.bar.com')
51 | expect(elevator.parse_tenant_name(request)).to eq('one.two.three.foo.bar.com')
52 | end
53 |
54 | it "should return host without www" do
55 | request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.one.two.three.bar.com')
56 | expect(elevator.parse_tenant_name(request)).to eq('one.two.three.bar.com')
57 | end
58 | end
59 | end
60 |
61 | context "assuming localhost" do
62 | it "should return localhost" do
63 | request = ActionDispatch::Request.new('HTTP_HOST' => 'localhost')
64 | expect(elevator.parse_tenant_name(request)).to eq('localhost')
65 | end
66 | end
67 |
68 | context "assuming ip address" do
69 | it "should return the ip address" do
70 | request = ActionDispatch::Request.new('HTTP_HOST' => '127.0.0.1')
71 | expect(elevator.parse_tenant_name(request)).to eq('127.0.0.1')
72 | end
73 | end
74 | end
75 |
76 | describe "#call" do
77 | it "switches to the proper tenant" do
78 | allow(described_class).to receive(:ignored_first_subdomains).and_return([])
79 | expect(Apartment::Tenant).to receive(:switch).with('foo.bar.com')
80 | elevator.call('HTTP_HOST' => 'foo.bar.com')
81 | end
82 |
83 | it "ignores ignored_first_subdomains" do
84 | allow(described_class).to receive(:ignored_first_subdomains).and_return(%w{foo})
85 | expect(Apartment::Tenant).to receive(:switch).with('bar.com')
86 | elevator.call('HTTP_HOST' => 'foo.bar.com')
87 | end
88 | end
89 | end
90 |
--------------------------------------------------------------------------------
/spec/unit/elevators/subdomain_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'apartment/elevators/subdomain'
3 |
4 | describe Apartment::Elevators::Subdomain do
5 |
6 | subject(:elevator){ described_class.new(Proc.new{}) }
7 |
8 | describe "#parse_tenant_name" do
9 | context "assuming one tld" do
10 | it "should parse subdomain" do
11 | request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com')
12 | expect(elevator.parse_tenant_name(request)).to eq('foo')
13 | end
14 |
15 | it "should return nil when no subdomain" do
16 | request = ActionDispatch::Request.new('HTTP_HOST' => 'bar.com')
17 | expect(elevator.parse_tenant_name(request)).to be_nil
18 | end
19 | end
20 |
21 | context "assuming two tlds" do
22 | it "should parse subdomain in the third level domain" do
23 | request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.co.uk')
24 | expect(elevator.parse_tenant_name(request)).to eq("foo")
25 | end
26 |
27 | it "should return nil when no subdomain in the third level domain" do
28 | request = ActionDispatch::Request.new('HTTP_HOST' => 'bar.co.uk')
29 | expect(elevator.parse_tenant_name(request)).to be_nil
30 | end
31 | end
32 |
33 | context "assuming two subdomains" do
34 | it "should parse two subdomains in the two level domain" do
35 | request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.xyz.bar.com')
36 | expect(elevator.parse_tenant_name(request)).to eq("foo")
37 | end
38 |
39 | it "should parse two subdomains in the third level domain" do
40 | request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.xyz.bar.co.uk')
41 | expect(elevator.parse_tenant_name(request)).to eq("foo")
42 | end
43 | end
44 |
45 | context "assuming localhost" do
46 | it "should return nil for localhost" do
47 | request = ActionDispatch::Request.new('HTTP_HOST' => 'localhost')
48 | expect(elevator.parse_tenant_name(request)).to be_nil
49 | end
50 | end
51 |
52 | context "assuming ip address" do
53 | it "should return nil for an ip address" do
54 | request = ActionDispatch::Request.new('HTTP_HOST' => '127.0.0.1')
55 | expect(elevator.parse_tenant_name(request)).to be_nil
56 | end
57 | end
58 | end
59 |
60 | describe "#call" do
61 | it "switches to the proper tenant" do
62 | expect(Apartment::Tenant).to receive(:switch).with('tenant1')
63 | elevator.call('HTTP_HOST' => 'tenant1.example.com')
64 | end
65 |
66 | it "ignores excluded subdomains" do
67 | described_class.excluded_subdomains = %w{foo}
68 |
69 | expect(Apartment::Tenant).not_to receive(:switch)
70 |
71 | elevator.call('HTTP_HOST' => 'foo.bar.com')
72 |
73 | described_class.excluded_subdomains = nil
74 | end
75 | end
76 | end
77 |
--------------------------------------------------------------------------------
/spec/unit/migrator_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'apartment/migrator'
3 |
4 | describe Apartment::Migrator do
5 |
6 | let(:tenant){ Apartment::Test.next_db }
7 |
8 | # Don't need a real switch here, just testing behaviour
9 | before { allow(Apartment::Tenant.adapter).to receive(:connect_to_new) }
10 |
11 | context "with ActiveRecord below 5.2.0", skip: ActiveRecord.version >= Gem::Version.new("5.2.0") do
12 | before do
13 | allow(ActiveRecord::Migrator).to receive(:migrations_paths) { %w(spec/dummy/db/migrate) }
14 | allow(Apartment::Migrator).to receive(:activerecord_below_5_2?) { true }
15 | end
16 |
17 | describe "::migrate" do
18 | it "switches and migrates" do
19 | expect(Apartment::Tenant).to receive(:switch).with(tenant).and_call_original
20 | expect(ActiveRecord::Migrator).to receive(:migrate)
21 |
22 | Apartment::Migrator.migrate(tenant)
23 | end
24 | end
25 |
26 | describe "::run" do
27 | it "switches and runs" do
28 | expect(Apartment::Tenant).to receive(:switch).with(tenant).and_call_original
29 | expect(ActiveRecord::Migrator).to receive(:run).with(:up, anything, 1234)
30 |
31 | Apartment::Migrator.run(:up, tenant, 1234)
32 | end
33 | end
34 |
35 | describe "::rollback" do
36 | it "switches and rolls back" do
37 | expect(Apartment::Tenant).to receive(:switch).with(tenant).and_call_original
38 | expect(ActiveRecord::Migrator).to receive(:rollback).with(anything, 2)
39 |
40 | Apartment::Migrator.rollback(tenant, 2)
41 | end
42 | end
43 | end
44 |
45 | context "with ActiveRecord above or equal to 5.2.0", skip: ActiveRecord.version < Gem::Version.new("5.2.0") do
46 | before do
47 | allow(Apartment::Migrator).to receive(:activerecord_below_5_2?) { false }
48 | end
49 |
50 | describe "::migrate" do
51 | it "switches and migrates" do
52 | expect(Apartment::Tenant).to receive(:switch).with(tenant).and_call_original
53 | expect_any_instance_of(ActiveRecord::MigrationContext).to receive(:migrate)
54 |
55 | Apartment::Migrator.migrate(tenant)
56 | end
57 | end
58 |
59 | describe "::run" do
60 | it "switches and runs" do
61 | expect(Apartment::Tenant).to receive(:switch).with(tenant).and_call_original
62 | expect_any_instance_of(ActiveRecord::MigrationContext).to receive(:run).with(:up, 1234)
63 |
64 | Apartment::Migrator.run(:up, tenant, 1234)
65 | end
66 | end
67 |
68 | describe "::rollback" do
69 | it "switches and rolls back" do
70 | expect(Apartment::Tenant).to receive(:switch).with(tenant).and_call_original
71 | expect_any_instance_of(ActiveRecord::MigrationContext).to receive(:rollback).with(2)
72 |
73 | Apartment::Migrator.rollback(tenant, 2)
74 | end
75 | end
76 | end
77 | end
78 |
--------------------------------------------------------------------------------
/spec/unit/reloader_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Apartment::Reloader do
4 |
5 | context "using postgresql schemas" do
6 |
7 | before do
8 | Apartment.configure do |config|
9 | config.excluded_models = ["Company"]
10 | config.use_schemas = true
11 | end
12 | Apartment::Tenant.reload!(config)
13 | Company.reset_table_name # ensure we're clean
14 | end
15 |
16 | subject{ Apartment::Reloader.new(double("Rack::Application", :call => nil)) }
17 |
18 | it "should initialize apartment when called" do
19 | expect(Company.table_name).not_to include('public.')
20 | subject.call(double('env'))
21 | expect(Company.table_name).to include('public.')
22 | end
23 | end
24 | end
--------------------------------------------------------------------------------