diff --git a/.circleci/config.yml b/.circleci/config.yml index 2f3e3c8b..6ae44ff4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,8 +1,5 @@ version: 2.1 -orbs: - rubocop: hanachin/rubocop@0.0.6 - jobs: build: docker: @@ -61,7 +58,10 @@ jobs: - run: name: Run tests - command: bundle exec rspec + command: bundle exec rspec --format progress --format RspecJunitFormatter -o ~/test-results/rspec/rspec.xml + + - store_test_results: + path: ~/test-results/rspec/ workflows: tests: @@ -69,10 +69,8 @@ workflows: - build: matrix: parameters: - ruby_version: ["ruby:2.6-buster", "ruby:2.7-buster"] + ruby_version: ["ruby:2.6-buster", "ruby:2.7-buster", "ruby:3.0-buster"] gemfile: ["gemfiles/rails_5_2.gemfile", "gemfiles/rails_6_0.gemfile", "gemfiles/rails_6_1.gemfile"] - - rubocop: - jobs: - - rubocop/rubocop: - version: 0.88.0 + exclude: + - ruby_version: "ruby:3.0-buster" + gemfile: "gemfiles/rails_5_2.gemfile" diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml new file mode 100644 index 00000000..6b1b315a --- /dev/null +++ b/.github/workflows/reviewdog.yml @@ -0,0 +1,22 @@ +name: reviewdog +on: [push, pull_request] +jobs: + rubocop: + name: runner / rubocop + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v2 + - name: Read ruby version + run: echo ::set-output name=RUBY_VERSION::$(cat .ruby-version | cut -f 1,2 -d .) + id: rv + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "${{ steps.rv.outputs.RUBY_VERSION }}" + - uses: reviewdog/action-rubocop@v1 + with: + filter_mode: nofilter + reporter: github-check + rubocop_version: 0.93.1 + github_token: ${{ secrets.github_token }} + rubocop_extensions: rubocop-performance:1.10.2 rubocop-rails:2.9.1 rubocop-rspec:1.44.1 diff --git a/.rubocop.yml b/.rubocop.yml index b7c5c8b6..998c5846 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,96 +1,32 @@ inherit_from: .rubocop_todo.yml -AllCops: - Exclude: - - 'gemfiles/**/*.gemfile' - - 'gemfiles/vendor/**/*' - - 'spec/dummy_engine/dummy_engine.gemspec' - -Gemspec/RequiredRubyVersion: - Exclude: - - 'ros-apartment.gemspec' +require: + - rubocop-rails + - rubocop-performance + - rubocop-rspec -Style/WordArray: +AllCops: Exclude: + - gemfiles/**/*.gemfile + - gemfiles/vendor/**/* + - spec/dummy_engine/dummy_engine.gemspec - spec/schemas/**/*.rb -Style/NumericLiterals: - Exclude: - - spec/schemas/**/*.rb + NewCops: enable -Layout/EmptyLineAfterMagicComment: +Gemspec/RequiredRubyVersion: Exclude: - - spec/schemas/**/*.rb + - 'ros-apartment.gemspec' Metrics/BlockLength: Exclude: - spec/**/*.rb -Layout/EmptyLinesAroundAttributeAccessor: - Enabled: true - -Layout/SpaceAroundMethodCallOperator: - Enabled: true - -Lint/DeprecatedOpenSSLConstant: - Enabled: true - -Lint/DuplicateElsifCondition: - Enabled: true - -Lint/MixedRegexpCaptureTypes: - Enabled: true - -Lint/RaiseException: - Enabled: true - -Lint/StructNewOverride: - Enabled: true - -Style/AccessorGrouping: - Enabled: true - -Style/ArrayCoercion: - Enabled: true - -Style/BisectedAttrAccessor: - Enabled: true - -Style/CaseLikeIf: - Enabled: true - -Style/ExponentialNotation: - Enabled: true - -Style/HashAsLastArrayItem: - Enabled: true - -Style/HashEachMethods: - Enabled: true - -Style/HashLikeCase: - Enabled: true - -Style/HashTransformKeys: - Enabled: true - -Style/HashTransformValues: - Enabled: true - -Style/RedundantAssignment: - Enabled: true - -Style/RedundantFetchBlock: - Enabled: true - -Style/RedundantFileExtensionInRequire: - Enabled: true - -Style/RedundantRegexpCharacterClass: - Enabled: true +Rails/RakeEnvironment: + Enabled: false -Style/RedundantRegexpEscape: - Enabled: true +Rails/ApplicationRecord: + Enabled: false -Style/SlicingWithRange: - Enabled: true +Rails/Output: + Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index c72ac883..3650e125 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2020-07-16 04:15:41 UTC using RuboCop version 0.88.0. +# on 2021-06-26 03:25:28 UTC using RuboCop version 0.93.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -11,22 +11,16 @@ Lint/MixedRegexpCaptureTypes: Exclude: - 'lib/apartment/elevators/domain.rb' -# Offense count: 2 -# Cop supports --auto-correct. -Lint/NonDeterministicRequireOrder: - Exclude: - - 'spec/spec_helper.rb' - -# Offense count: 7 +# Offense count: 3 # Configuration parameters: IgnoredMethods. Metrics/AbcSize: - Max: 33 + Max: 28 -# Offense count: 3 +# Offense count: 5 # Configuration parameters: CountComments, CountAsOne, ExcludedMethods. # ExcludedMethods: refine Metrics/BlockLength: - Max: 102 + Max: 83 # Offense count: 1 # Configuration parameters: CountComments, CountAsOne. @@ -38,6 +32,193 @@ Metrics/ClassLength: Metrics/MethodLength: Max: 24 +# Offense count: 3 +RSpec/AnyInstance: + Exclude: + - 'spec/unit/migrator_spec.rb' + +# Offense count: 2 +RSpec/BeforeAfterAll: + Exclude: + - 'spec/spec_helper.rb' + - 'spec/rails_helper.rb' + - 'spec/support/**/*.rb' + - 'spec/adapters/sqlite3_adapter_spec.rb' + - 'spec/tasks/apartment_rake_spec.rb' + +# Offense count: 18 +# Configuration parameters: Prefixes. +# Prefixes: when, with, without +RSpec/ContextWording: + Exclude: + - 'spec/adapters/sqlite3_adapter_spec.rb' + - 'spec/examples/generic_adapter_custom_configuration_example.rb' + - 'spec/examples/schema_adapter_examples.rb' + - 'spec/support/contexts.rb' + - 'spec/tasks/apartment_rake_spec.rb' + - 'spec/tenant_spec.rb' + +# Offense count: 4 +# Configuration parameters: IgnoredMetadata. +RSpec/DescribeClass: + Exclude: + - 'spec/integration/apartment_rake_integration_spec.rb' + - 'spec/integration/query_caching_spec.rb' + - 'spec/integration/use_within_an_engine_spec.rb' + - 'spec/tasks/apartment_rake_spec.rb' + +# Offense count: 12 +# Cop supports --auto-correct. +# Configuration parameters: SkipBlocks, EnforcedStyle. +# SupportedStyles: described_class, explicit +RSpec/DescribedClass: + Exclude: + - 'spec/apartment_spec.rb' + - 'spec/tenant_spec.rb' + - 'spec/unit/elevators/host_hash_spec.rb' + - 'spec/unit/migrator_spec.rb' + - 'spec/unit/reloader_spec.rb' + +# Offense count: 5 +# Cop supports --auto-correct. +RSpec/EmptyLineAfterFinalLet: + Exclude: + - 'spec/adapters/sqlite3_adapter_spec.rb' + - 'spec/examples/schema_adapter_examples.rb' + +# Offense count: 14 +# Configuration parameters: Max. +RSpec/ExampleLength: + Exclude: + - 'spec/examples/generic_adapter_custom_configuration_example.rb' + - 'spec/examples/generic_adapter_examples.rb' + - 'spec/examples/schema_adapter_examples.rb' + - 'spec/integration/query_caching_spec.rb' + - 'spec/tenant_spec.rb' + +# Offense count: 60 +# Cop supports --auto-correct. +# Configuration parameters: CustomTransform, IgnoredWords. +RSpec/ExampleWording: + Exclude: + - 'spec/adapters/sqlite3_adapter_spec.rb' + - 'spec/apartment_spec.rb' + - 'spec/examples/connection_adapter_examples.rb' + - 'spec/examples/generic_adapter_custom_configuration_example.rb' + - 'spec/examples/generic_adapter_examples.rb' + - 'spec/examples/schema_adapter_examples.rb' + - 'spec/integration/apartment_rake_integration_spec.rb' + - 'spec/integration/use_within_an_engine_spec.rb' + - 'spec/tasks/apartment_rake_spec.rb' + - 'spec/tenant_spec.rb' + +# Offense count: 13 +# Configuration parameters: CustomTransform, IgnoreMethods, SpecSuffixOnly. +RSpec/FilePath: + Exclude: + - 'spec/adapters/mysql2_adapter_spec.rb' + - 'spec/adapters/postgresql_adapter_spec.rb' + - 'spec/adapters/sqlite3_adapter_spec.rb' + - 'spec/tenant_spec.rb' + - 'spec/unit/config_spec.rb' + - 'spec/unit/elevators/domain_spec.rb' + - 'spec/unit/elevators/first_subdomain_spec.rb' + - 'spec/unit/elevators/generic_spec.rb' + - 'spec/unit/elevators/host_hash_spec.rb' + - 'spec/unit/elevators/host_spec.rb' + - 'spec/unit/elevators/subdomain_spec.rb' + - 'spec/unit/migrator_spec.rb' + - 'spec/unit/reloader_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: implicit, each, example +RSpec/HookArgument: + Exclude: + - 'spec/support/setup.rb' + +# Offense count: 4 +# Cop supports --auto-correct. +RSpec/HooksBeforeExamples: + Exclude: + - 'spec/adapters/sqlite3_adapter_spec.rb' + - 'spec/examples/schema_adapter_examples.rb' + +# Offense count: 18 +# Configuration parameters: AssignmentOnly. +RSpec/InstanceVariable: + Exclude: + - 'spec/examples/generic_adapter_examples.rb' + - 'spec/examples/schema_adapter_examples.rb' + - 'spec/integration/apartment_rake_integration_spec.rb' + - 'spec/integration/use_within_an_engine_spec.rb' + - 'spec/tasks/apartment_rake_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +RSpec/LeadingSubject: + Exclude: + - 'spec/unit/reloader_spec.rb' + +# Offense count: 2 +RSpec/LeakyConstantDeclaration: + Exclude: + - 'spec/examples/generic_adapters_callbacks_examples.rb' + - 'spec/unit/elevators/generic_spec.rb' + +# Offense count: 35 +# Configuration parameters: EnforcedStyle. +# SupportedStyles: have_received, receive +RSpec/MessageSpies: + Exclude: + - 'spec/examples/generic_adapter_custom_configuration_example.rb' + - 'spec/integration/apartment_rake_integration_spec.rb' + - 'spec/integration/use_within_an_engine_spec.rb' + - 'spec/tasks/apartment_rake_spec.rb' + - 'spec/unit/elevators/domain_spec.rb' + - 'spec/unit/elevators/generic_spec.rb' + - 'spec/unit/elevators/host_hash_spec.rb' + - 'spec/unit/elevators/host_spec.rb' + - 'spec/unit/elevators/subdomain_spec.rb' + - 'spec/unit/migrator_spec.rb' + +# Offense count: 29 +RSpec/MultipleExpectations: + Max: 4 + +# Offense count: 47 +# Configuration parameters: IgnoreSharedExamples. +RSpec/NamedSubject: + Exclude: + - 'spec/adapters/mysql2_adapter_spec.rb' + - 'spec/adapters/sqlite3_adapter_spec.rb' + - 'spec/support/contexts.rb' + - 'spec/support/requirements.rb' + - 'spec/tenant_spec.rb' + - 'spec/unit/reloader_spec.rb' + +# Offense count: 24 +RSpec/NestedGroups: + Max: 5 + +# Offense count: 6 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: and_return, block +RSpec/ReturnFromStub: + Exclude: + - 'spec/integration/apartment_rake_integration_spec.rb' + - 'spec/unit/migrator_spec.rb' + +# Offense count: 4 +# Configuration parameters: IgnoreNameless, IgnoreSymbolicNames. +RSpec/VerifiedDoubles: + Exclude: + - 'spec/integration/apartment_rake_integration_spec.rb' + - 'spec/unit/elevators/first_subdomain_spec.rb' + - 'spec/unit/reloader_spec.rb' + # Offense count: 17 Style/Documentation: Exclude: @@ -56,11 +237,3 @@ Style/Documentation: - 'lib/apartment/tasks/enhancements.rb' - 'lib/apartment/tasks/task_helper.rb' - 'lib/generators/apartment/install/install_generator.rb' - -# Offense count: 3 -# Cop supports --auto-correct. -Style/IfUnlessModifier: - Exclude: - - 'Rakefile' - - 'lib/apartment.rb' - - 'lib/apartment/tenant.rb' diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 00000000..2c9b4ef4 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.7.3 diff --git a/Gemfile b/Gemfile index 0949319d..f7200f13 100644 --- a/Gemfile +++ b/Gemfile @@ -3,11 +3,3 @@ source 'http://rubygems.org' gemspec - -gem 'rails', '>= 3.1.2' -gem 'rubocop' - -group :local do - gem 'guard-rspec', '~> 4.2' - gem 'pry' -end diff --git a/README.md b/README.md index fa033c09..4ffc9231 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,16 @@ switched back at the end of the block to what it was before. There is also `switch!` which doesn't take a block, but it's recommended to use `switch`. To return to the default tenant, you can call `switch` with no arguments. +#### Multiple Tenants + +When using schemas, you can also pass in a list of schemas if desired. Any tables defined in a schema earlier in the chain will be referenced first, so this is only useful if you have a schema with only some of the tables defined: + +```ruby +Apartment::Tenant.switch(['tenant_1', 'tenant_2']) do + # ... +end +``` + ### Switching Tenants per request You can have Apartment route to the appropriate tenant by adding some Rack middleware. diff --git a/lib/apartment.rb b/lib/apartment.rb index a9506fd9..8a774b5b 100644 --- a/lib/apartment.rb +++ b/lib/apartment.rb @@ -107,13 +107,13 @@ def connection_class def database_schema_file return @database_schema_file if defined?(@database_schema_file) - @database_schema_file = Rails.root.join('db', 'schema.rb') + @database_schema_file = Rails.root.join('db/schema.rb') end def seed_data_file return @seed_data_file if defined?(@seed_data_file) - @seed_data_file = Rails.root.join('db', 'seeds.rb') + @seed_data_file = Rails.root.join('db/seeds.rb') end def pg_excluded_names diff --git a/lib/apartment/adapters/jdbc_postgresql_adapter.rb b/lib/apartment/adapters/jdbc_postgresql_adapter.rb index 70dbadf3..3e9494b0 100644 --- a/lib/apartment/adapters/jdbc_postgresql_adapter.rb +++ b/lib/apartment/adapters/jdbc_postgresql_adapter.rb @@ -38,11 +38,9 @@ class JDBCPostgresqlSchemaAdapter < PostgresqlSchemaAdapter # def connect_to_new(tenant = nil) return reset if tenant.nil? + raise ActiveRecord::StatementInvalid, "Could not find schema #{tenant}" unless schema_exists?(tenant) - tenant = tenant.to_s - raise ActiveRecord::StatementInvalid, "Could not find schema #{tenant}" unless tenant_exists?(tenant) - - @current = tenant + @current = tenant.is_a?(Array) ? tenant.map(&:to_s) : tenant.to_s Apartment.connection.schema_search_path = full_search_path rescue ActiveRecord::StatementInvalid, ActiveRecord::JDBCError raise TenantNotFound, "One of the following schema(s) is invalid: #{full_search_path}" diff --git a/lib/apartment/adapters/postgresql_adapter.rb b/lib/apartment/adapters/postgresql_adapter.rb index 9540f016..5d7f9e21 100644 --- a/lib/apartment/adapters/postgresql_adapter.rb +++ b/lib/apartment/adapters/postgresql_adapter.rb @@ -72,11 +72,9 @@ def drop_command(conn, tenant) # def connect_to_new(tenant = nil) return reset if tenant.nil? + raise ActiveRecord::StatementInvalid, "Could not find schema #{tenant}" unless schema_exists?(tenant) - tenant = tenant.to_s - raise ActiveRecord::StatementInvalid, "Could not find schema #{tenant}" unless tenant_exists?(tenant) - - @current = tenant + @current = tenant.is_a?(Array) ? tenant.map(&:to_s) : tenant.to_s Apartment.connection.schema_search_path = full_search_path # When the PostgreSQL version is < 9.3, @@ -149,6 +147,12 @@ def reset_sequence_names c.remove_instance_variable :@sequence_name if c.instance_variable_defined?(:@sequence_name) end end + + def schema_exists?(schemas) + return true unless Apartment.tenant_presence_check + + Array(schemas).all? { |schema| Apartment.connection.schema_exists?(schema.to_s) } + end end # Another Adapter for Postgresql when using schemas and SQL @@ -158,6 +162,7 @@ class PostgresqlSchemaFromSqlAdapter < PostgresqlSchemaAdapter /SET lock_timeout/i, # new in postgresql 9.3 /SET row_security/i, # new in postgresql 9.5 /SET idle_in_transaction_session_timeout/i, # new in postgresql 9.6 + /SET default_table_access_method/i, # new in postgresql 12 /CREATE SCHEMA public/i, /COMMENT ON SCHEMA public/i @@ -224,7 +229,7 @@ def pg_dump_schema_migrations_data # Temporary set Postgresql related environment variables if there are in @config # - def with_pg_env(&block) + def with_pg_env pghost = ENV['PGHOST'] pgport = ENV['PGPORT'] pguser = ENV['PGUSER'] @@ -235,7 +240,7 @@ def with_pg_env(&block) ENV['PGUSER'] = @config[:username].to_s if @config[:username] ENV['PGPASSWORD'] = @config[:password].to_s if @config[:password] - block.call + yield ensure ENV['PGHOST'] = pghost ENV['PGPORT'] = pgport diff --git a/lib/apartment/model.rb b/lib/apartment/model.rb index 5a75a140..8401cd64 100644 --- a/lib/apartment/model.rb +++ b/lib/apartment/model.rb @@ -17,7 +17,9 @@ def cached_find_by_statement(key, &block) cache_key = if key.is_a? String "#{Apartment::Tenant.current}_#{key}" else - [Apartment::Tenant.current] + key + # NOTE: In Rails 6.0.4 we start receiving an ActiveRecord::Reflection::BelongsToReflection + # as the key, which wouldn't work well with an array. + [Apartment::Tenant.current] + Array.wrap(key) end cache = @find_by_statement_cache[connection.prepared_statements] cache.compute_if_absent(cache_key) { ActiveRecord::StatementCache.create(connection, &block) } diff --git a/lib/apartment/railtie.rb b/lib/apartment/railtie.rb index 649c6fcd..ba4e5728 100644 --- a/lib/apartment/railtie.rb +++ b/lib/apartment/railtie.rb @@ -32,7 +32,7 @@ class Railtie < Rails::Railtie # config.to_prepare do next if ARGV.any? { |arg| arg =~ /\Aassets:(?:precompile|clean)\z/ } - next if ARGV.any? { |arg| arg == 'webpacker:compile' } + next if ARGV.any?('webpacker:compile') next if ENV['APARTMENT_DISABLE_INIT'] begin @@ -74,11 +74,9 @@ class Railtie < Rails::Railtie # Overrides reload! to also call Apartment::Tenant.init as well # so that the reloaded classes have the proper table_names - # rubocop:disable Lint/Debugger console do require 'apartment/console' end - # rubocop:enable Lint/Debugger end end end diff --git a/lib/apartment/version.rb b/lib/apartment/version.rb index 7ec53121..31deaf81 100644 --- a/lib/apartment/version.rb +++ b/lib/apartment/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Apartment - VERSION = '2.9.0' + VERSION = '2.10.0' end diff --git a/lib/tasks/apartment.rake b/lib/tasks/apartment.rake index 5ae47c0f..6cb74393 100644 --- a/lib/tasks/apartment.rake +++ b/lib/tasks/apartment.rake @@ -17,12 +17,10 @@ apartment_namespace = namespace :apartment do desc 'Drop all tenants' task :drop do Apartment::TaskHelper.tenants.each do |tenant| - begin - puts("Dropping #{tenant} tenant") - Apartment::Tenant.drop(tenant) - rescue Apartment::TenantNotFound, ActiveRecord::NoDatabaseError => e - puts e.message - end + puts("Dropping #{tenant} tenant") + Apartment::Tenant.drop(tenant) + rescue Apartment::TenantNotFound, ActiveRecord::NoDatabaseError => e + puts e.message end end @@ -39,15 +37,13 @@ apartment_namespace = namespace :apartment do Apartment::TaskHelper.warn_if_tenants_empty Apartment::TaskHelper.each_tenant do |tenant| - begin - Apartment::TaskHelper.create_tenant(tenant) - puts("Seeding #{tenant} tenant") - Apartment::Tenant.switch(tenant) do - Apartment::Tenant.seed - end - rescue Apartment::TenantNotFound => e - puts e.message + Apartment::TaskHelper.create_tenant(tenant) + puts("Seeding #{tenant} tenant") + Apartment::Tenant.switch(tenant) do + Apartment::Tenant.seed end + rescue Apartment::TenantNotFound => e + puts e.message end end @@ -58,12 +54,10 @@ apartment_namespace = namespace :apartment do step = ENV['STEP'] ? ENV['STEP'].to_i : 1 Apartment::TaskHelper.each_tenant do |tenant| - begin - puts("Rolling back #{tenant} tenant") - Apartment::Migrator.rollback tenant, step - rescue Apartment::TenantNotFound => e - puts e.message - end + puts("Rolling back #{tenant} tenant") + Apartment::Migrator.rollback tenant, step + rescue Apartment::TenantNotFound => e + puts e.message end end @@ -76,12 +70,10 @@ apartment_namespace = namespace :apartment do raise 'VERSION is required' unless version Apartment::TaskHelper.each_tenant do |tenant| - begin - puts("Migrating #{tenant} tenant up") - Apartment::Migrator.run :up, tenant, version - rescue Apartment::TenantNotFound => e - puts e.message - end + puts("Migrating #{tenant} tenant up") + Apartment::Migrator.run :up, tenant, version + rescue Apartment::TenantNotFound => e + puts e.message end end @@ -93,12 +85,10 @@ apartment_namespace = namespace :apartment do raise 'VERSION is required' unless version Apartment::TaskHelper.each_tenant do |tenant| - begin - puts("Migrating #{tenant} tenant down") - Apartment::Migrator.run :down, tenant, version - rescue Apartment::TenantNotFound => e - puts e.message - end + puts("Migrating #{tenant} tenant down") + Apartment::Migrator.run :down, tenant, version + rescue Apartment::TenantNotFound => e + puts e.message end end diff --git a/ros-apartment.gemspec b/ros-apartment.gemspec index 95a60c35..169865c4 100644 --- a/ros-apartment.gemspec +++ b/ros-apartment.gemspec @@ -27,17 +27,23 @@ Gem::Specification.new do |s| s.homepage = 'https://github.com/rails-on-services/apartment' s.licenses = ['MIT'] - s.add_dependency 'activerecord', '>= 5.0.0', '< 6.2' - s.add_dependency 'parallel', '< 2.0' - s.add_dependency 'public_suffix', '>= 2.0.5', '< 5.0' - s.add_dependency 'rack', '>= 1.3.6', '< 3.0' + s.add_dependency 'activerecord', '>= 5.0.0', '< 6.2' + s.add_dependency 'parallel', '< 2.0' + s.add_dependency 'public_suffix', '>= 2.0.5', '< 5.0' + s.add_dependency 'rack', '>= 1.3.6', '< 3.0' - s.add_development_dependency 'appraisal', '~> 2.2' - s.add_development_dependency 'bundler', '>= 1.3', '< 3.0' - s.add_development_dependency 'capybara', '~> 2.0' - s.add_development_dependency 'rake', '~> 13.0' - s.add_development_dependency 'rspec', '~> 3.4' - s.add_development_dependency 'rspec-rails', '~> 3.4' + s.add_development_dependency 'appraisal', '~> 2.2' + s.add_development_dependency 'bundler', '>= 1.3', '< 3.0' + s.add_development_dependency 'guard-rspec', '~> 4.2' + s.add_development_dependency 'pry' + s.add_development_dependency 'rake', '~> 13.0' + s.add_development_dependency 'rspec', '~> 3.4' + s.add_development_dependency 'rspec_junit_formatter' + s.add_development_dependency 'rspec-rails', '~> 3.4' + s.add_development_dependency 'rubocop', '~> 0.93' + s.add_development_dependency 'rubocop-performance', '~> 1.10' + s.add_development_dependency 'rubocop-rails', '~> 2.1' + s.add_development_dependency 'rubocop-rspec', '~> 1.44' if defined?(JRUBY_VERSION) s.add_development_dependency 'activerecord-jdbc-adapter' diff --git a/spec/adapters/jdbc_mysql_adapter_spec.rb b/spec/adapters/jdbc_mysql_adapter_spec.rb index 2d0fb975..b757c96b 100644 --- a/spec/adapters/jdbc_mysql_adapter_spec.rb +++ b/spec/adapters/jdbc_mysql_adapter_spec.rb @@ -16,8 +16,8 @@ def tenant_names let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.current_database } } - it_should_behave_like 'a generic apartment adapter callbacks' - it_should_behave_like 'a generic apartment adapter' - it_should_behave_like 'a connection based apartment adapter' + it_behaves_like 'a generic apartment adapter callbacks' + it_behaves_like 'a generic apartment adapter' + it_behaves_like 'a connection based apartment adapter' end end diff --git a/spec/adapters/jdbc_postgresql_adapter_spec.rb b/spec/adapters/jdbc_postgresql_adapter_spec.rb index 67d3c981..d1deabf3 100644 --- a/spec/adapters/jdbc_postgresql_adapter_spec.rb +++ b/spec/adapters/jdbc_postgresql_adapter_spec.rb @@ -8,9 +8,9 @@ describe Apartment::Adapters::JDBCPostgresqlAdapter, database: :postgresql do subject { Apartment::Tenant.jdbc_postgresql_adapter config.symbolize_keys } - it_should_behave_like 'a generic apartment adapter callbacks' + it_behaves_like 'a generic apartment adapter callbacks' - context 'using schemas' do + context 'when using schemas' do before { Apartment.use_schemas = true } # Not sure why, but somehow using let(:tenant_names) memoizes for the whole example group, not just each test @@ -18,13 +18,13 @@ def tenant_names ActiveRecord::Base.connection.execute('SELECT nspname FROM pg_namespace;').collect { |row| row['nspname'] } end - let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.schema_search_path.gsub('"', '') } } + let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.schema_search_path.delete('"') } } - it_should_behave_like 'a generic apartment adapter' - it_should_behave_like 'a schema based apartment adapter' + it_behaves_like 'a generic apartment adapter' + it_behaves_like 'a schema based apartment adapter' end - context 'using databases' do + context 'when using databases' do before { Apartment.use_schemas = false } # Not sure why, but somehow using let(:tenant_names) memoizes for the whole example group, not just each test @@ -34,8 +34,8 @@ def tenant_names let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.current_database } } - it_should_behave_like 'a generic apartment adapter' - it_should_behave_like 'a connection based apartment adapter' + it_behaves_like 'a generic apartment adapter' + it_behaves_like 'a connection based apartment adapter' end end end diff --git a/spec/adapters/mysql2_adapter_spec.rb b/spec/adapters/mysql2_adapter_spec.rb index 505b7d6b..fea994f4 100644 --- a/spec/adapters/mysql2_adapter_spec.rb +++ b/spec/adapters/mysql2_adapter_spec.rb @@ -16,12 +16,12 @@ def tenant_names let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.current_database } } - it_should_behave_like 'a generic apartment adapter callbacks' + it_behaves_like 'a generic apartment adapter callbacks' - context 'using - the equivalent of - schemas' do + context 'when using - the equivalent of - schemas' do before { Apartment.use_schemas = true } - it_should_behave_like 'a generic apartment adapter' + it_behaves_like 'a generic apartment adapter' describe '#default_tenant' do it 'is set to the original db from config' do @@ -46,7 +46,7 @@ def tenant_names end end - it 'should process model exclusions' do + it 'processes model exclusions' do Apartment::Tenant.init expect(Company.table_name).to eq("#{default_tenant}.companies") @@ -54,12 +54,12 @@ def tenant_names end end - context 'using connections' do + context 'when using connections' do before { Apartment.use_schemas = false } - it_should_behave_like 'a generic apartment adapter' - it_should_behave_like 'a generic apartment adapter able to handle custom configuration' - it_should_behave_like 'a connection based apartment adapter' + it_behaves_like 'a generic apartment adapter' + it_behaves_like 'a generic apartment adapter able to handle custom configuration' + it_behaves_like 'a connection based apartment adapter' end end end diff --git a/spec/adapters/postgresql_adapter_spec.rb b/spec/adapters/postgresql_adapter_spec.rb index d7689d26..7944c862 100644 --- a/spec/adapters/postgresql_adapter_spec.rb +++ b/spec/adapters/postgresql_adapter_spec.rb @@ -8,9 +8,9 @@ subject { Apartment::Tenant.postgresql_adapter config } - it_should_behave_like 'a generic apartment adapter callbacks' + it_behaves_like 'a generic apartment adapter callbacks' - context 'using schemas with schema.rb' do + context 'when using schemas with schema.rb' do before { Apartment.use_schemas = true } # Not sure why, but somehow using let(:tenant_names) memoizes for the whole example group, not just each test @@ -18,38 +18,38 @@ def tenant_names ActiveRecord::Base.connection.execute('SELECT nspname FROM pg_namespace;').collect { |row| row['nspname'] } end - let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.schema_search_path.gsub('"', '') } } + let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.schema_search_path.delete('"') } } - it_should_behave_like 'a generic apartment adapter' - it_should_behave_like 'a schema based apartment adapter' + it_behaves_like 'a generic apartment adapter' + it_behaves_like 'a schema based apartment adapter' end - context 'using schemas with SQL dump' do + context 'when using schemas with SQL dump' do before do Apartment.use_schemas = true Apartment.use_sql = true end + after do + Apartment::Tenant.drop('has-dashes') if Apartment.connection.schema_exists? 'has-dashes' + end + # Not sure why, but somehow using let(:tenant_names) memoizes for the whole example group, not just each test def tenant_names ActiveRecord::Base.connection.execute('SELECT nspname FROM pg_namespace;').collect { |row| row['nspname'] } end - let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.schema_search_path.gsub('"', '') } } + let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.schema_search_path.delete('"') } } - it_should_behave_like 'a generic apartment adapter' - it_should_behave_like 'a schema based apartment adapter' + it_behaves_like 'a generic apartment adapter' + it_behaves_like 'a schema based apartment adapter' it 'allows for dashes in the schema name' do - expect { Apartment::Tenant.create('has-dashes') }.to_not raise_error - end - - after do - Apartment::Tenant.drop('has-dashes') if Apartment.connection.schema_exists? 'has-dashes' + expect { Apartment::Tenant.create('has-dashes') }.not_to raise_error end end - context 'using connections' do + context 'when using connections' do before { Apartment.use_schemas = false } # Not sure why, but somehow using let(:tenant_names) memoizes for the whole example group, not just each test @@ -59,9 +59,9 @@ def tenant_names let(:default_tenant) { subject.switch { ActiveRecord::Base.connection.current_database } } - it_should_behave_like 'a generic apartment adapter' - it_should_behave_like 'a generic apartment adapter able to handle custom configuration' - it_should_behave_like 'a connection based apartment adapter' + it_behaves_like 'a generic apartment adapter' + it_behaves_like 'a generic apartment adapter able to handle custom configuration' + it_behaves_like 'a connection based apartment adapter' end end end diff --git a/spec/adapters/sqlite3_adapter_spec.rb b/spec/adapters/sqlite3_adapter_spec.rb index f05c76ba..1581a3e3 100644 --- a/spec/adapters/sqlite3_adapter_spec.rb +++ b/spec/adapters/sqlite3_adapter_spec.rb @@ -8,7 +8,7 @@ subject { Apartment::Tenant.sqlite3_adapter config } - it_should_behave_like 'a generic apartment adapter callbacks' + it_behaves_like 'a generic apartment adapter callbacks' context 'using connections' do def tenant_names @@ -20,8 +20,8 @@ def tenant_names subject.switch { File.basename(Apartment::Test.config['connections']['sqlite']['database'], '.sqlite3') } end - it_should_behave_like 'a generic apartment adapter' - it_should_behave_like 'a connection based apartment adapter' + it_behaves_like 'a generic apartment adapter' + it_behaves_like 'a connection based apartment adapter' after(:all) do File.delete(Apartment::Test.config['connections']['sqlite']['database']) @@ -40,11 +40,9 @@ def tenant_names end after do - begin - subject.drop db_name - rescue StandardError => _e - nil - end + subject.drop db_name + rescue StandardError => _e + nil end it 'should create a new database' do @@ -61,11 +59,9 @@ def tenant_names end after do - begin - subject.drop db_name - rescue StandardError => _e - nil - end + subject.drop db_name + rescue StandardError => _e + nil end it 'should create a new database' do @@ -85,11 +81,9 @@ def tenant_names end after do - begin - subject.drop db_name - rescue StandardError => _e - nil - end + subject.drop db_name + rescue StandardError => _e + nil end it 'should create a new database' do diff --git a/spec/examples/generic_adapter_examples.rb b/spec/examples/generic_adapter_examples.rb index cbe6013f..8289b3f9 100644 --- a/spec/examples/generic_adapter_examples.rb +++ b/spec/examples/generic_adapter_examples.rb @@ -132,7 +132,7 @@ expect do subject.switch(db1) { subject.drop(db2) } - end.to_not raise_error + end.not_to raise_error end end diff --git a/spec/examples/schema_adapter_examples.rb b/spec/examples/schema_adapter_examples.rb index 447322e3..586dce62 100644 --- a/spec/examples/schema_adapter_examples.rb +++ b/spec/examples/schema_adapter_examples.rb @@ -81,7 +81,7 @@ it 'should allow them' do expect do subject.create(db) - end.to_not raise_error + end.not_to raise_error expect(tenant_names).to include(db.to_s) end @@ -103,16 +103,14 @@ subject.create(db) expect do subject.drop(db) - end.to_not raise_error + end.not_to raise_error expect(tenant_names).not_to include(db.to_s) end after do - begin - subject.drop(db) - rescue StandardError => _e - nil - end + subject.drop(db) + rescue StandardError => _e + nil end end end @@ -127,6 +125,13 @@ expect(connection.schema_search_path).to start_with %("#{public_schema}") expect(User.sequence_name).to eq "#{public_schema}.#{User.table_name}_id_seq" end + + it 'allows a list of schemas' do + subject.switch([schema1, schema2]) do + expect(connection.schema_search_path).to include %("#{schema1}") + expect(connection.schema_search_path).to include %("#{schema2}") + end + end end describe '#reset' do @@ -192,7 +197,7 @@ it 'should not raise any errors' do expect do subject.switch! 'unknown_schema' - end.to_not raise_error(Apartment::TenantNotFound) + end.not_to raise_error(Apartment::TenantNotFound) end end @@ -203,7 +208,7 @@ subject.create(db) expect do subject.switch!(db) - end.to_not raise_error + end.not_to raise_error expect(connection.schema_search_path).to start_with %("#{db}") end diff --git a/spec/integration/apartment_rake_integration_spec.rb b/spec/integration/apartment_rake_integration_spec.rb index fbfd0474..64fcd644 100644 --- a/spec/integration/apartment_rake_integration_spec.rb +++ b/spec/integration/apartment_rake_integration_spec.rb @@ -32,7 +32,7 @@ context 'with x number of databases' do let(:x) { rand(1..5) } # random number of dbs to create - let(:db_names) { x.times.map { Apartment::Test.next_db } } + let(:db_names) { Array.new(x).map { Apartment::Test.next_db } } let!(:company_count) { db_names.length } before do diff --git a/spec/integration/use_within_an_engine_spec.rb b/spec/integration/use_within_an_engine_spec.rb index 072efac6..f3269ba4 100644 --- a/spec/integration/use_within_an_engine_spec.rb +++ b/spec/integration/use_within_an_engine_spec.rb @@ -11,17 +11,17 @@ end it 'sucessfully runs rake db:migrate in the engine root' do - expect { Rake::Task['db:migrate'].invoke }.to_not raise_error + expect { Rake::Task['db:migrate'].invoke }.not_to raise_error end it 'sucessfully runs rake app:db:migrate in the engine root' do - expect { Rake::Task['app:db:migrate'].invoke }.to_not raise_error + expect { Rake::Task['app:db:migrate'].invoke }.not_to raise_error end context 'when Apartment.db_migrate_tenants is false' do it 'should not enhance tasks' do Apartment.db_migrate_tenants = false - expect(Apartment::RakeTaskEnhancer).to_not receive(:enhance_task).with('db:migrate') + expect(Apartment::RakeTaskEnhancer).not_to receive(:enhance_task).with('db:migrate') Rake::Task['db:migrate'].invoke end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f5ba6bbe..138f719e 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -19,17 +19,15 @@ end require 'rspec/rails' -require 'capybara/rspec' -require 'capybara/rails' -# rubocop:disable Lint/ConstantDefinitionInBlock begin require 'pry' + # rubocop:disable Lint/ConstantDefinitionInBlock silence_warnings { IRB = Pry } + # rubocop:enable Lint/ConstantDefinitionInBlock rescue LoadError nil end -# rubocop:enable Lint/ConstantDefinitionInBlock ActionMailer::Base.delivery_method = :test ActionMailer::Base.perform_deliveries = true @@ -38,10 +36,9 @@ Rails.backtrace_cleaner.remove_silencers! # Load support files -Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } +Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].sort.each { |f| require f } RSpec.configure do |config| - config.include RSpec::Integration::CapybaraSessions, type: :request config.include Apartment::Spec::Setup # Somewhat brutal hack so that rails 4 postgres extensions don't modify this file @@ -62,4 +59,4 @@ end # Load shared examples, must happen after configure for RSpec 3 -Dir["#{File.dirname(__FILE__)}/examples/**/*.rb"].each { |f| require f } +Dir["#{File.dirname(__FILE__)}/examples/**/*.rb"].sort.each { |f| require f } diff --git a/spec/support/capybara_sessions.rb b/spec/support/capybara_sessions.rb deleted file mode 100644 index def4985c..00000000 --- a/spec/support/capybara_sessions.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -module RSpec - module Integration - module CapybaraSessions - def in_new_session(&_block) - yield new_session - end - - def new_session - Capybara::Session.new(Capybara.current_driver, Capybara.app) - end - end - end -end diff --git a/spec/tasks/apartment_rake_spec.rb b/spec/tasks/apartment_rake_spec.rb index f71727a9..e75c8c92 100644 --- a/spec/tasks/apartment_rake_spec.rb +++ b/spec/tasks/apartment_rake_spec.rb @@ -31,7 +31,7 @@ let(:version) { '1234' } context 'database migration' do - let(:tenant_names) { 3.times.map { Apartment::Test.next_db } } + let(:tenant_names) { Array(3).map { Apartment::Test.next_db } } let(:tenant_count) { tenant_names.length } before do diff --git a/spec/tenant_spec.rb b/spec/tenant_spec.rb index e3aacf04..13363b9a 100644 --- a/spec/tenant_spec.rb +++ b/spec/tenant_spec.rb @@ -13,24 +13,6 @@ end end - # TODO: this doesn't belong here, but there aren't integration tests currently for mysql - # where to put??? - describe 'exception recovery', type: :request do - before do - subject.create db1 - end - after { subject.drop db1 } - - # it "should recover from incorrect database" do - # session = Capybara::Session.new(:rack_test, Capybara.app) - # session.visit("http://#{db1}.com") - # expect { - # session.visit("http://this-database-should-not-exist.com") - # }.to raise_error - # session.visit("http://#{db1}.com") - # end - end - # TODO: re-organize these tests context 'with prefix and schemas' do describe '#create' do @@ -44,11 +26,9 @@ end after do - begin - subject.drop 'db_with_prefix' - rescue StandardError => _e - nil - end + subject.drop 'db_with_prefix' + rescue StandardError => _e + nil end it 'should create a new database' do @@ -79,6 +59,7 @@ context 'threadsafety' do before { subject.create db1 } + after { subject.drop db1 } it 'has a threadsafe adapter' do @@ -115,6 +96,7 @@ context 'creating models' do before { subject.create db2 } + after { subject.drop db2 } it 'should create a model instance in the current schema' do @@ -182,7 +164,7 @@ it 'should seed from custom path' do Apartment.configure do |config| - config.seed_data_file = Rails.root.join('db', 'seeds', 'import.rb') + config.seed_data_file = Rails.root.join('db/seeds/import.rb') end subject.create db1 subject.switch! db1 diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb index 9adaf84c..c15514da 100644 --- a/spec/unit/config_spec.rb +++ b/spec/unit/config_spec.rb @@ -5,7 +5,7 @@ describe Apartment do describe '#config' do let(:excluded_models) { ['Company'] } - let(:seed_data_file_path) { Rails.root.join('db', 'seeds', 'import.rb') } + let(:seed_data_file_path) { Rails.root.join('db/seeds/import.rb') } def tenant_names_from_array(names) names.each_with_object({}) do |tenant, hash| @@ -13,111 +13,111 @@ def tenant_names_from_array(names) end.with_indifferent_access end - it 'should yield the Apartment object' do - Apartment.configure do |config| + it 'yields the Apartment object' do + described_class.configure do |config| config.excluded_models = [] - expect(config).to eq(Apartment) + expect(config).to eq(described_class) end end - it 'should set excluded models' do - Apartment.configure do |config| + it 'sets excluded models' do + described_class.configure do |config| config.excluded_models = excluded_models end - expect(Apartment.excluded_models).to eq(excluded_models) + expect(described_class.excluded_models).to eq(excluded_models) end - it 'should set use_schemas' do - Apartment.configure do |config| + it 'sets use_schemas' do + described_class.configure do |config| config.excluded_models = [] config.use_schemas = false end - expect(Apartment.use_schemas).to be false + expect(described_class.use_schemas).to be false end - it 'should set seed_data_file' do - Apartment.configure do |config| + it 'sets seed_data_file' do + described_class.configure do |config| config.seed_data_file = seed_data_file_path end - expect(Apartment.seed_data_file).to eq(seed_data_file_path) + expect(described_class.seed_data_file).to eq(seed_data_file_path) end - it 'should set seed_after_create' do - Apartment.configure do |config| + it 'sets seed_after_create' do + described_class.configure do |config| config.excluded_models = [] config.seed_after_create = true end - expect(Apartment.seed_after_create).to be true + expect(described_class.seed_after_create).to be true end - it 'should set tenant_presence_check' do - Apartment.configure do |config| + it 'sets tenant_presence_check' do + described_class.configure do |config| config.tenant_presence_check = true end - expect(Apartment.tenant_presence_check).to be true + expect(described_class.tenant_presence_check).to be true end - it 'should set active_record_log' do - Apartment.configure do |config| + it 'sets active_record_log' do + described_class.configure do |config| config.active_record_log = true end - expect(Apartment.active_record_log).to be true + expect(described_class.active_record_log).to be true end - context 'databases' do + context 'when databases' do let(:users_conf_hash) { { port: 5444 } } before do - Apartment.configure do |config| + described_class.configure do |config| config.tenant_names = tenant_names end end - context 'tenant_names as string array' do + context 'when tenant_names as string array' do let(:tenant_names) { %w[users companies] } - it 'should return object if it doesnt respond_to call' do - expect(Apartment.tenant_names).to eq(tenant_names_from_array(tenant_names).keys) + it 'returns object if it doesnt respond_to call' do + expect(described_class.tenant_names).to eq(tenant_names_from_array(tenant_names).keys) end - it 'should set tenants_with_config' do - expect(Apartment.tenants_with_config).to eq(tenant_names_from_array(tenant_names)) + it 'sets tenants_with_config' do + expect(described_class.tenants_with_config).to eq(tenant_names_from_array(tenant_names)) end end - context 'tenant_names as proc returning an array' do + context 'when tenant_names as proc returning an array' do let(:tenant_names) { -> { %w[users companies] } } - it 'should return object if it doesnt respond_to call' do - expect(Apartment.tenant_names).to eq(tenant_names_from_array(tenant_names.call).keys) + it 'returns object if it doesnt respond_to call' do + expect(described_class.tenant_names).to eq(tenant_names_from_array(tenant_names.call).keys) end - it 'should set tenants_with_config' do - expect(Apartment.tenants_with_config).to eq(tenant_names_from_array(tenant_names.call)) + it 'sets tenants_with_config' do + expect(described_class.tenants_with_config).to eq(tenant_names_from_array(tenant_names.call)) end end - context 'tenant_names as Hash' do + context 'when tenant_names as Hash' do let(:tenant_names) { { users: users_conf_hash }.with_indifferent_access } - it 'should return object if it doesnt respond_to call' do - expect(Apartment.tenant_names).to eq(tenant_names.keys) + it 'returns object if it doesnt respond_to call' do + expect(described_class.tenant_names).to eq(tenant_names.keys) end - it 'should set tenants_with_config' do - expect(Apartment.tenants_with_config).to eq(tenant_names) + it 'sets tenants_with_config' do + expect(described_class.tenants_with_config).to eq(tenant_names) end end - context 'tenant_names as proc returning a Hash' do + context 'when tenant_names as proc returning a Hash' do let(:tenant_names) { -> { { users: users_conf_hash }.with_indifferent_access } } - it 'should return object if it doesnt respond_to call' do - expect(Apartment.tenant_names).to eq(tenant_names.call.keys) + it 'returns object if it doesnt respond_to call' do + expect(described_class.tenant_names).to eq(tenant_names.call.keys) end - it 'should set tenants_with_config' do - expect(Apartment.tenants_with_config).to eq(tenant_names.call) + it 'sets tenants_with_config' do + expect(described_class.tenants_with_config).to eq(tenant_names.call) end end end diff --git a/spec/unit/elevators/first_subdomain_spec.rb b/spec/unit/elevators/first_subdomain_spec.rb index f608d834..fc36a109 100644 --- a/spec/unit/elevators/first_subdomain_spec.rb +++ b/spec/unit/elevators/first_subdomain_spec.rb @@ -6,20 +6,24 @@ describe Apartment::Elevators::FirstSubdomain do describe 'subdomain' do subject { described_class.new('test').parse_tenant_name(request) } + let(:request) { double(:request, host: "#{subdomain}.example.com") } - context 'one subdomain' do + context 'when one subdomain' do let(:subdomain) { 'test' } + it { is_expected.to eq('test') } end - context 'nested subdomains' do + context 'when nested subdomains' do let(:subdomain) { 'test1.test2' } + it { is_expected.to eq('test1') } end - context 'no subdomain' do + context 'when no subdomain' do let(:subdomain) { nil } + it { is_expected.to eq(nil) } end end diff --git a/spec/unit/elevators/host_spec.rb b/spec/unit/elevators/host_spec.rb index e0cb9c3c..f8d77949 100644 --- a/spec/unit/elevators/host_spec.rb +++ b/spec/unit/elevators/host_spec.rb @@ -7,66 +7,74 @@ subject(:elevator) { described_class.new(proc {}) } describe '#parse_tenant_name' do - it 'should return nil when no host' do + it 'returns nil when no host' do request = ActionDispatch::Request.new('HTTP_HOST' => '') expect(elevator.parse_tenant_name(request)).to be_nil end - context 'assuming no ignored_first_subdomains' do + context 'when assuming no ignored_first_subdomains' do before { allow(described_class).to receive(:ignored_first_subdomains).and_return([]) } context 'with 3 parts' do - it 'should return the whole host' do + it 'returns the whole host' do request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com') expect(elevator.parse_tenant_name(request)).to eq('foo.bar.com') end end context 'with 6 parts' do - it 'should return the whole host' do + it 'returns the whole host' do request = ActionDispatch::Request.new('HTTP_HOST' => 'one.two.three.foo.bar.com') expect(elevator.parse_tenant_name(request)).to eq('one.two.three.foo.bar.com') end end end - context 'assuming ignored_first_subdomains is set' do + context 'when assuming ignored_first_subdomains is set' do before { allow(described_class).to receive(:ignored_first_subdomains).and_return(%w[www foo]) } context 'with 3 parts' do - it 'should return host without www' do + it 'returns host without www' do request = ActionDispatch::Request.new('HTTP_HOST' => 'www.bar.com') expect(elevator.parse_tenant_name(request)).to eq('bar.com') end - it 'should return host without foo' do + it 'returns host without foo' do request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com') expect(elevator.parse_tenant_name(request)).to eq('bar.com') end end context 'with 6 parts' do - it 'should return host without www' do - request = ActionDispatch::Request.new('HTTP_HOST' => 'www.one.two.three.foo.bar.com') - expect(elevator.parse_tenant_name(request)).to eq('one.two.three.foo.bar.com') + context 'when ignored subdomains do not match in the begining' do + let(:http_host) { 'www.one.two.three.foo.bar.com' } + + it 'returns host without www' do + request = ActionDispatch::Request.new('HTTP_HOST' => http_host) + expect(elevator.parse_tenant_name(request)).to eq('one.two.three.foo.bar.com') + end end - it 'should return host without www' do - request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.one.two.three.bar.com') - expect(elevator.parse_tenant_name(request)).to eq('one.two.three.bar.com') + context 'when ignored subdomains match in the begining' do + let(:http_host) { 'foo.one.two.three.bar.com' } + + it 'returns host without matching subdomain' do + request = ActionDispatch::Request.new('HTTP_HOST' => http_host) + expect(elevator.parse_tenant_name(request)).to eq('one.two.three.bar.com') + end end end end - context 'assuming localhost' do - it 'should return localhost' do + context 'when assuming localhost' do + it 'returns localhost' do request = ActionDispatch::Request.new('HTTP_HOST' => 'localhost') expect(elevator.parse_tenant_name(request)).to eq('localhost') end end - context 'assuming ip address' do - it 'should return the ip address' do + context 'when assuming ip address' do + it 'returns the ip address' do request = ActionDispatch::Request.new('HTTP_HOST' => '127.0.0.1') expect(elevator.parse_tenant_name(request)).to eq('127.0.0.1') end diff --git a/spec/unit/elevators/subdomain_spec.rb b/spec/unit/elevators/subdomain_spec.rb index 4c66ce67..b1cd8f4b 100644 --- a/spec/unit/elevators/subdomain_spec.rb +++ b/spec/unit/elevators/subdomain_spec.rb @@ -7,51 +7,51 @@ subject(:elevator) { described_class.new(proc {}) } describe '#parse_tenant_name' do - context 'assuming one tld' do - it 'should parse subdomain' do + context 'when assuming one tld' do + it 'parses subdomain' do request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com') expect(elevator.parse_tenant_name(request)).to eq('foo') end - it 'should return nil when no subdomain' do + it 'returns nil when no subdomain' do request = ActionDispatch::Request.new('HTTP_HOST' => 'bar.com') expect(elevator.parse_tenant_name(request)).to be_nil end end - context 'assuming two tlds' do - it 'should parse subdomain in the third level domain' do + context 'when assuming two tlds' do + it 'parses subdomain in the third level domain' do request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.co.uk') expect(elevator.parse_tenant_name(request)).to eq('foo') end - it 'should return nil when no subdomain in the third level domain' do + it 'returns nil when no subdomain in the third level domain' do request = ActionDispatch::Request.new('HTTP_HOST' => 'bar.co.uk') expect(elevator.parse_tenant_name(request)).to be_nil end end - context 'assuming two subdomains' do - it 'should parse two subdomains in the two level domain' do + context 'when assuming two subdomains' do + it 'parses two subdomains in the two level domain' do request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.xyz.bar.com') expect(elevator.parse_tenant_name(request)).to eq('foo') end - it 'should parse two subdomains in the third level domain' do + it 'parses two subdomains in the third level domain' do request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.xyz.bar.co.uk') expect(elevator.parse_tenant_name(request)).to eq('foo') end end - context 'assuming localhost' do - it 'should return nil for localhost' do + context 'when assuming localhost' do + it 'returns nil for localhost' do request = ActionDispatch::Request.new('HTTP_HOST' => 'localhost') expect(elevator.parse_tenant_name(request)).to be_nil end end - context 'assuming ip address' do - it 'should return nil for an ip address' do + context 'when assuming ip address' do + it 'returns nil for an ip address' do request = ActionDispatch::Request.new('HTTP_HOST' => '127.0.0.1') expect(elevator.parse_tenant_name(request)).to be_nil end diff --git a/spec/unit/reloader_spec.rb b/spec/unit/reloader_spec.rb index 54bd2ff7..b194a46c 100644 --- a/spec/unit/reloader_spec.rb +++ b/spec/unit/reloader_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Apartment::Reloader do - context 'using postgresql schemas' do + context 'when using postgresql schemas' do before do Apartment.configure do |config| config.excluded_models = ['Company'] @@ -15,7 +15,7 @@ subject { Apartment::Reloader.new(double('Rack::Application', call: nil)) } - it 'should initialize apartment when called' do + it 'initializes apartment when called' do expect(Company.table_name).not_to include('public.') subject.call(double('env')) expect(Company.table_name).to include('public.')