apartment 0.22.1 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -2
  3. data/.rspec +2 -1
  4. data/.travis.yml +3 -1
  5. data/Appraisals +7 -0
  6. data/Gemfile +0 -21
  7. data/HISTORY.md +6 -0
  8. data/README.md +13 -71
  9. data/Rakefile +4 -2
  10. data/TODO.md +0 -5
  11. data/apartment.gemspec +19 -0
  12. data/gemfiles/rails3.2.gemfile +7 -0
  13. data/gemfiles/rails4.0.gemfile +7 -0
  14. data/lib/apartment.rb +2 -28
  15. data/lib/apartment/adapters/abstract_adapter.rb +0 -2
  16. data/lib/apartment/adapters/abstract_jdbc_adapter.rb +2 -0
  17. data/lib/apartment/adapters/jdbc_mysql_adapter.rb +2 -0
  18. data/lib/apartment/adapters/jdbc_postgresql_adapter.rb +1 -1
  19. data/lib/apartment/adapters/mysql2_adapter.rb +2 -3
  20. data/lib/apartment/adapters/postgis_adapter.rb +0 -1
  21. data/lib/apartment/adapters/postgresql_adapter.rb +2 -3
  22. data/lib/apartment/adapters/sqlite3_adapter.rb +2 -0
  23. data/lib/apartment/database.rb +0 -4
  24. data/lib/apartment/elevators/domain.rb +2 -0
  25. data/lib/apartment/elevators/first_subdomain.rb +2 -0
  26. data/lib/apartment/elevators/generic.rb +3 -0
  27. data/lib/apartment/elevators/host_hash.rb +2 -0
  28. data/lib/apartment/elevators/subdomain.rb +19 -2
  29. data/lib/apartment/migrator.rb +2 -1
  30. data/lib/apartment/railtie.rb +2 -2
  31. data/lib/apartment/reloader.rb +0 -3
  32. data/lib/apartment/version.rb +2 -2
  33. data/lib/tasks/apartment.rake +2 -0
  34. data/spec/adapters/jdbc_mysql_adapter_spec.rb +1 -3
  35. data/spec/adapters/jdbc_postgresql_adapter_spec.rb +1 -3
  36. data/spec/adapters/mysql2_adapter_spec.rb +1 -2
  37. data/spec/adapters/postgresql_adapter_spec.rb +1 -2
  38. data/spec/adapters/sqlite3_adapter_spec.rb +1 -2
  39. data/spec/database_spec.rb +32 -50
  40. data/spec/dummy/app/models/user.rb +0 -2
  41. data/spec/dummy/config/application.rb +2 -0
  42. data/spec/dummy/config/environments/development.rb +2 -0
  43. data/spec/dummy/config/environments/production.rb +2 -0
  44. data/spec/dummy/config/environments/test.rb +1 -2
  45. data/spec/dummy/config/initializers/apartment.rb +1 -1
  46. data/spec/dummy/db/seeds.rb +1 -4
  47. data/spec/examples/elevator_examples.rb +4 -4
  48. data/spec/integration/apartment_rake_integration_spec.rb +15 -19
  49. data/spec/integration/middleware/domain_elevator_spec.rb +4 -3
  50. data/spec/integration/middleware/generic_elevator_spec.rb +4 -3
  51. data/spec/integration/middleware/subdomain_elevator_spec.rb +29 -3
  52. data/spec/integration/query_caching_spec.rb +8 -4
  53. data/spec/schemas/v1.rb +16 -0
  54. data/spec/schemas/v2.rb +43 -0
  55. data/spec/schemas/v3.rb +49 -0
  56. data/spec/spec_helper.rb +5 -11
  57. data/spec/support/apartment_helpers.rb +4 -2
  58. data/spec/support/contexts.rb +15 -19
  59. data/spec/support/requirements.rb +1 -17
  60. data/spec/support/setup.rb +47 -0
  61. data/spec/tasks/apartment_rake_spec.rb +6 -3
  62. data/spec/unit/config_spec.rb +3 -3
  63. data/spec/unit/middleware/domain_elevator_spec.rb +1 -2
  64. data/spec/{integration → unit}/middleware/first_subdomain_elevator_spec.rb +1 -0
  65. data/spec/unit/middleware/host_hash_elevator_spec.rb +1 -2
  66. data/spec/unit/middleware/subdomain_elevator_spec.rb +1 -2
  67. data/spec/unit/migrator_spec.rb +5 -4
  68. data/spec/unit/reloader_spec.rb +6 -4
  69. metadata +130 -14
  70. data/lib/apartment/delayed_job/enqueue.rb +0 -26
  71. data/lib/apartment/delayed_job/hooks.rb +0 -26
  72. data/lib/apartment/delayed_job/psych_ext.rb +0 -61
  73. data/lib/apartment/delayed_job/requirements.rb +0 -23
  74. data/lib/apartment/delayed_job/syck_ext.rb +0 -29
  75. data/spec/dummy/lib/fake_dj_class.rb +0 -6
  76. data/spec/integration/delayed_job_integration_spec.rb +0 -99
@@ -1,34 +1,34 @@
1
1
  require 'spec_helper'
2
2
  require 'rake'
3
3
 
4
- describe "apartment rake tasks" do
4
+ describe "apartment rake tasks", database: :postgresql do
5
5
 
6
6
  before do
7
7
  @rake = Rake::Application.new
8
8
  Rake.application = @rake
9
9
  Dummy::Application.load_tasks
10
10
 
11
- # somehow this misc.rake file gets lost in the shuffle
12
- # it defines a `rails_env` task that our db:migrate depends on
13
- # No idea why, but during the tests, we somehow lose this tasks, so we get an error when testing migrations
14
- # This is STUPID!
15
- load "rails/tasks/misc.rake"
16
- end
17
-
18
- after do
19
- Rake.application = nil
20
- end
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')
21
18
 
22
- before do
23
19
  Apartment.configure do |config|
20
+ config.use_schemas = true
24
21
  config.excluded_models = ["Company"]
25
- config.database_names = lambda{ Company.scoped.collect(&:database) }
22
+ config.database_names = lambda{ Company.pluck(:database) }
26
23
  end
24
+ Apartment::Database.reload!(config)
27
25
 
28
26
  # fix up table name of shared/excluded models
29
27
  Company.table_name = 'public.companies'
30
28
  end
31
29
 
30
+ after { Rake.application = nil }
31
+
32
32
  context "with x number of databases" do
33
33
 
34
34
  let(:x){ 1 + rand(5) } # random number of dbs to create
@@ -49,7 +49,7 @@ describe "apartment rake tasks" do
49
49
 
50
50
  describe "#migrate" do
51
51
  it "should migrate all databases" do
52
- Apartment::Migrator.should_receive(:migrate).exactly(company_count).times
52
+ ActiveRecord::Migrator.should_receive(:migrate).exactly(company_count+1).times
53
53
 
54
54
  @rake['apartment:migrate'].invoke
55
55
  end
@@ -57,12 +57,9 @@ describe "apartment rake tasks" do
57
57
 
58
58
  describe "#rollback" do
59
59
  it "should rollback all dbs" do
60
- db_names.each do |name|
61
- Apartment::Migrator.should_receive(:rollback).with(name, anything)
62
- end
60
+ ActiveRecord::Migrator.should_receive(:rollback).exactly(company_count+1).times
63
61
 
64
62
  @rake['apartment:rollback'].invoke
65
- @rake['apartment:migrate'].invoke # migrate again so that our next test 'seed' can run (requires migrations to be complete)
66
63
  end
67
64
  end
68
65
 
@@ -73,6 +70,5 @@ describe "apartment rake tasks" do
73
70
  @rake['apartment:seed'].invoke
74
71
  end
75
72
  end
76
-
77
73
  end
78
74
  end
@@ -1,9 +1,10 @@
1
1
  require 'spec_helper'
2
+ require 'apartment/elevators/domain'
2
3
 
3
- describe Apartment::Elevators::Domain, :elevator => true do
4
+ describe Apartment::Elevators::Domain, elevator: true do
4
5
 
5
- let(:domain1) { "http://#{database1}.com" }
6
- let(:domain2) { "http://#{database2}.com" }
6
+ let(:domain1) { "http://#{db1}.com" }
7
+ let(:domain2) { "http://#{db2}.com" }
7
8
 
8
9
  it_should_behave_like "an apartment elevator"
9
10
  end
@@ -1,10 +1,11 @@
1
1
  require 'spec_helper'
2
+ require 'apartment/elevators/generic'
2
3
 
3
- describe Apartment::Elevators::Generic, :elevator => true do
4
+ describe Apartment::Elevators::Generic, elevator: true do
4
5
 
5
6
  # NOTE, see spec/dummy/config/application.rb to see the Proc that defines the behaviour here
6
- let(:domain1) { "http://#{database1}.com?db=#{database1}" }
7
- let(:domain2) { "http://#{database2}.com?db=#{database2}" }
7
+ let(:domain1) { "http://#{db1}.com?db=#{db1}" }
8
+ let(:domain2) { "http://#{db2}.com?db=#{db2}" }
8
9
 
9
10
  it_should_behave_like "an apartment elevator"
10
11
  end
@@ -1,9 +1,35 @@
1
1
  require 'spec_helper'
2
+ require 'apartment/elevators/generic'
2
3
 
3
- describe Apartment::Elevators::Subdomain, :elevator => true do
4
+ describe Apartment::Elevators::Subdomain, elevator: true do
4
5
 
5
- let(:domain1) { "http://#{database1}.example.com" }
6
- let(:domain2) { "http://#{database2}.example.com" }
6
+ let(:domain1) { "http://#{db1}.example.com" }
7
+ let(:domain2) { "http://#{db2}.example.com" }
7
8
 
8
9
  it_should_behave_like "an apartment elevator"
10
+
11
+ context "With Subdomain Excluded" do
12
+ let(:domain_with_excluded_subdomain) { "http://www.example.com" }
13
+
14
+ before do
15
+ Apartment::Elevators::Subdomain.excluded_subdomains = %w(www)
16
+ # FIXME:
17
+ # This is used because the dummy app includes all three middlewares. The domain middleware specifically
18
+ # tries to lookup the example schema and tries to switch to it. I don't know how to go around this.
19
+ Apartment::Database.create("example")
20
+ end
21
+
22
+ it_should_behave_like "an apartment elevator"
23
+
24
+ it "shouldnt switch the schema if the subdomain is excluded" do
25
+ ActiveRecord::Base.connection.schema_search_path.scan(/\w+/).should_not include("www")
26
+ visit(domain_with_excluded_subdomain)
27
+ ActiveRecord::Base.connection.schema_search_path.scan(/\w+/).should_not include("www")
28
+ end
29
+
30
+ after do
31
+ Apartment::Elevators::Subdomain.excluded_subdomains = []
32
+ Apartment::Database.drop("example")
33
+ end
34
+ end
9
35
  end
@@ -1,25 +1,29 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'query caching' do
4
+ let(:db_names) { [db1, db2] }
5
+
4
6
  before do
5
7
  Apartment.configure do |config|
6
8
  config.excluded_models = ["Company"]
7
- config.database_names = lambda{ Company.scoped.collect(&:database) }
9
+ config.database_names = lambda{ Company.pluck(:database) }
10
+ config.use_schemas = true
8
11
  end
9
12
 
13
+ Apartment::Database.reload!(config)
14
+
10
15
  db_names.each do |db_name|
11
16
  Apartment::Database.create(db_name)
12
- Company.create :database => db_name
17
+ Company.create database: db_name
13
18
  end
14
19
  end
15
20
 
16
21
  after do
17
22
  db_names.each{ |db| Apartment::Database.drop(db) }
23
+ Apartment::Database.reset
18
24
  Company.delete_all
19
25
  end
20
26
 
21
- let(:db_names) { 2.times.map{ Apartment::Test.next_db } }
22
-
23
27
  it 'clears the ActiveRecord::QueryCache after switching databases' do
24
28
  db_names.each do |db_name|
25
29
  Apartment::Database.switch db_name
@@ -0,0 +1,16 @@
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
@@ -0,0 +1,43 @@
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
@@ -0,0 +1,49 @@
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
data/spec/spec_helper.rb CHANGED
@@ -23,21 +23,15 @@ Rails.backtrace_cleaner.remove_silencers!
23
23
  # Load support files
24
24
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
25
25
 
26
-
27
26
  RSpec.configure do |config|
28
27
 
29
- config.include RSpec::Integration::CapybaraSessions, :type => :request
30
-
31
- config.before(:all) do
32
- # Ensure that each test starts with a clean connection
33
- # Necessary as some tests will leak things like current_schema into the next test
34
- ActiveRecord::Base.clear_all_connections!
35
- end
28
+ config.include RSpec::Integration::CapybaraSessions, type: :request
29
+ config.include Apartment::Spec::Setup
36
30
 
37
- config.after(:each) do
38
- Apartment.reset
31
+ # Somewhat brutal hack so that rails 4 postgres extensions don't modify this file
32
+ config.after(:suite) do
33
+ `git checkout -- spec/dummy/db/schema.rb`
39
34
  end
40
-
41
35
  end
42
36
 
43
37
  # Load shared examples, must happen after configure for RSpec 3
@@ -25,8 +25,10 @@ module Apartment
25
25
  ActiveRecord::Base.connection.execute("CREATE SCHEMA #{schema}")
26
26
  end
27
27
 
28
- def load_schema
29
- silence_stream(STDOUT){ load(Rails.root.join('db', 'schema.rb')) }
28
+ def load_schema(version = 3)
29
+ file = File.expand_path("../../schemas/v#{version}.rb", __FILE__)
30
+
31
+ silence_stream(STDOUT){ load(file) }
30
32
  end
31
33
 
32
34
  def migrate
@@ -16,28 +16,24 @@ shared_context "with default schema", :default_schema => true do
16
16
  end
17
17
 
18
18
  # Some default setup for elevator specs
19
- shared_context "elevators", :elevator => true do
20
- let(:company1) { mock_model(Company, :database => Apartment::Test.next_db).as_null_object }
21
- let(:company2) { mock_model(Company, :database => Apartment::Test.next_db).as_null_object }
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
22
 
23
- let(:database1) { company1.database }
24
- let(:database2) { company2.database }
23
+ let(:api) { Apartment::Database }
25
24
 
26
- let(:api) { Apartment::Database }
27
-
28
- before do
29
- Apartment.reset # reset all config
30
- Apartment.seed_after_create = false
31
- Apartment.use_schemas = true
32
- api.reload! # reload adapter
33
-
34
- api.create(database1)
35
- api.create(database2)
36
- end
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
37
33
 
38
- after do
39
- api.drop(database1)
40
- api.drop(database2)
34
+ after do
35
+ api.drop(db1)
36
+ api.drop(db2)
41
37
  end
42
38
  end
43
39
 
@@ -11,14 +11,8 @@ module Apartment
11
11
  extend ActiveSupport::Concern
12
12
 
13
13
  included do
14
- let(:db1){ Apartment::Test.next_db }
15
- let(:db2){ Apartment::Test.next_db }
16
- let(:connection){ ActiveRecord::Base.connection }
17
14
 
18
15
  before do
19
- Apartment::Database.reload!(config.symbolize_keys)
20
- ActiveRecord::Base.establish_connection config
21
-
22
16
  subject.create(db1)
23
17
  subject.create(db2)
24
18
  end
@@ -30,20 +24,10 @@ module Apartment
30
24
  # sometimes we manually drop these schemas in testing, don't care if we can't drop, hence rescue
31
25
  subject.drop(db1) rescue true
32
26
  subject.drop(db2) rescue true
33
-
34
- # This is annoying, but for each sublcass that establishes its own connection (ie Company for excluded models for connection based adapters)
35
- # a separate connection is maintained (clear_all_connections! doesn't appear to deal with these)
36
- # This causes problems because previous tests that established this connection could F up the next test, so we'll just remove them all for each test :(
37
- Apartment.excluded_models.each do |m|
38
- klass = m.constantize
39
- Apartment.connection_class.remove_connection(klass)
40
- klass.reset_table_name
41
- end
42
- ActiveRecord::Base.clear_all_connections!
43
27
  end
44
28
  end
45
29
 
46
- %w{subject config database_names default_database}.each do |method|
30
+ %w{subject database_names default_database}.each do |method|
47
31
  define_method method do
48
32
  raise "You must define a `#{method}` method in your host group"
49
33
  end unless defined?(method)
@@ -0,0 +1,47 @@
1
+ module Apartment
2
+ module Spec
3
+ module Setup
4
+
5
+ def self.included(base)
6
+ base.instance_eval do
7
+ let(:config){ database_config }
8
+
9
+ let(:db1){ Apartment::Test.next_db }
10
+ let(:db2){ Apartment::Test.next_db }
11
+ let(:connection){ ActiveRecord::Base.connection }
12
+
13
+ # This around ensures that we run these hooks before and after
14
+ # any before/after hooks defined in individual tests
15
+ # Otherwise these actually get run after test defined hooks
16
+ around(:each) do |example|
17
+ # before
18
+ Apartment::Database.reload!(config)
19
+ ActiveRecord::Base.establish_connection config
20
+
21
+ example.run
22
+
23
+ # after
24
+ Rails.configuration.database_configuration = {}
25
+ ActiveRecord::Base.clear_all_connections!
26
+
27
+ Apartment.excluded_models.each do |model|
28
+ klass = model.constantize
29
+
30
+ Apartment.connection_class.remove_connection(klass)
31
+ klass.clear_all_connections!
32
+ klass.reset_table_name
33
+ end
34
+
35
+ Apartment.reset
36
+ Apartment::Database.reload!
37
+ end
38
+ end
39
+ end
40
+
41
+ def database_config
42
+ db = example.metadata.fetch(:database, :postgresql)
43
+ Apartment::Test.config['connections'][db.to_s].symbolize_keys
44
+ end
45
+ end
46
+ end
47
+ end