dr-apartment 0.14.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/.gitignore +6 -0
  2. data/.rspec +2 -0
  3. data/.rvmrc +1 -0
  4. data/Gemfile +22 -0
  5. data/HISTORY.md +133 -0
  6. data/README.md +152 -0
  7. data/Rakefile +79 -0
  8. data/apartment.gemspec +32 -0
  9. data/lib/apartment.rb +69 -0
  10. data/lib/apartment/adapters/abstract_adapter.rb +176 -0
  11. data/lib/apartment/adapters/jdbcpostgresql_adapter.rb +115 -0
  12. data/lib/apartment/adapters/mysql_adapter.rb +18 -0
  13. data/lib/apartment/adapters/postgresql_adapter.rb +114 -0
  14. data/lib/apartment/console.rb +12 -0
  15. data/lib/apartment/database.rb +57 -0
  16. data/lib/apartment/delayed_job/active_record.rb +20 -0
  17. data/lib/apartment/delayed_job/enqueue.rb +20 -0
  18. data/lib/apartment/delayed_job/hooks.rb +25 -0
  19. data/lib/apartment/delayed_job/requirements.rb +23 -0
  20. data/lib/apartment/elevators/subdomain.rb +27 -0
  21. data/lib/apartment/migrator.rb +23 -0
  22. data/lib/apartment/railtie.rb +54 -0
  23. data/lib/apartment/reloader.rb +24 -0
  24. data/lib/apartment/version.rb +3 -0
  25. data/lib/tasks/apartment.rake +70 -0
  26. data/spec/adapters/mysql_adapter_spec.rb +36 -0
  27. data/spec/adapters/postgresql_adapter_spec.rb +137 -0
  28. data/spec/apartment_spec.rb +11 -0
  29. data/spec/config/database.yml +13 -0
  30. data/spec/dummy/Rakefile +7 -0
  31. data/spec/dummy/app/controllers/application_controller.rb +6 -0
  32. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  33. data/spec/dummy/app/models/company.rb +3 -0
  34. data/spec/dummy/app/models/user.rb +3 -0
  35. data/spec/dummy/app/views/application/index.html.erb +1 -0
  36. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  37. data/spec/dummy/config.ru +4 -0
  38. data/spec/dummy/config/application.rb +47 -0
  39. data/spec/dummy/config/boot.rb +10 -0
  40. data/spec/dummy/config/database.yml +16 -0
  41. data/spec/dummy/config/environment.rb +5 -0
  42. data/spec/dummy/config/environments/development.rb +26 -0
  43. data/spec/dummy/config/environments/production.rb +49 -0
  44. data/spec/dummy/config/environments/test.rb +35 -0
  45. data/spec/dummy/config/initializers/apartment.rb +4 -0
  46. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  47. data/spec/dummy/config/initializers/inflections.rb +10 -0
  48. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  49. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  50. data/spec/dummy/config/initializers/session_store.rb +8 -0
  51. data/spec/dummy/config/locales/en.yml +5 -0
  52. data/spec/dummy/config/routes.rb +3 -0
  53. data/spec/dummy/db/migrate/20110613152810_create_dummy_models.rb +37 -0
  54. data/spec/dummy/db/migrate/20111202022214_create_table_books.rb +13 -0
  55. data/spec/dummy/db/schema.rb +48 -0
  56. data/spec/dummy/db/seeds.rb +8 -0
  57. data/spec/dummy/db/test.sqlite3 +0 -0
  58. data/spec/dummy/lib/fake_dj_class.rb +6 -0
  59. data/spec/dummy/public/404.html +26 -0
  60. data/spec/dummy/public/422.html +26 -0
  61. data/spec/dummy/public/500.html +26 -0
  62. data/spec/dummy/public/favicon.ico +0 -0
  63. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  64. data/spec/dummy/script/rails +6 -0
  65. data/spec/integration/apartment_rake_integration_spec.rb +74 -0
  66. data/spec/integration/database_integration_spec.rb +200 -0
  67. data/spec/integration/delayed_job_integration_spec.rb +100 -0
  68. data/spec/integration/middleware/subdomain_elevator_spec.rb +63 -0
  69. data/spec/spec_helper.rb +31 -0
  70. data/spec/support/apartment_helpers.rb +32 -0
  71. data/spec/support/capybara_sessions.rb +15 -0
  72. data/spec/support/config.rb +11 -0
  73. data/spec/tasks/apartment_rake_spec.rb +118 -0
  74. data/spec/unit/config_spec.rb +78 -0
  75. data/spec/unit/middleware/subdomain_elevator_spec.rb +20 -0
  76. data/spec/unit/migrator_spec.rb +87 -0
  77. data/spec/unit/reloader_spec.rb +22 -0
  78. metadata +144 -0
@@ -0,0 +1,8 @@
1
+ def create_users
2
+ 3.times do |x|
3
+ user = User.find_or_initialize_by_name "Some User #{x}"
4
+ user.save
5
+ end
6
+ end
7
+
8
+ create_users
@@ -0,0 +1,6 @@
1
+ class FakeDjClass
2
+
3
+ def perform
4
+ end
5
+
6
+ end
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/404.html -->
21
+ <div class="dialog">
22
+ <h1>The page you were looking for doesn't exist.</h1>
23
+ <p>You may have mistyped the address or the page may have moved.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/422.html -->
21
+ <div class="dialog">
22
+ <h1>The change you wanted was rejected.</h1>
23
+ <p>Maybe you tried to change something you didn't have access to.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/500.html -->
21
+ <div class="dialog">
22
+ <h1>We're sorry, but something went wrong.</h1>
23
+ <p>We've been notified about this issue and we'll take a look at it shortly.</p>
24
+ </div>
25
+ </body>
26
+ </html>
File without changes
File without changes
@@ -0,0 +1,6 @@
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'
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+ require 'rake'
3
+
4
+ describe "apartment rake tasks" do
5
+
6
+ before do
7
+ @rake = Rake::Application.new
8
+ Rake.application = @rake
9
+ Dummy::Application.load_tasks
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
21
+
22
+ before do
23
+ Apartment.configure do |config|
24
+ config.excluded_models = ["Company"]
25
+ config.database_names = lambda{ Company.scoped.collect(&:database) }
26
+ end
27
+ end
28
+
29
+ context "with x number of databases" do
30
+
31
+ let(:x){ 1 + rand(5) } # random number of dbs to create
32
+ let(:db_names){ x.times.map{|y| "database_#{y}" } }
33
+
34
+ before do
35
+ db_names.collect do |db_name|
36
+ Apartment::Database.create(db_name)
37
+ Company.create :database => db_name
38
+ end
39
+ end
40
+
41
+ after do
42
+ db_names.each{ |db| Apartment::Database.drop(db) }
43
+ Company.delete_all
44
+ end
45
+
46
+ describe "#migrate" do
47
+ it "should migrate all databases" do
48
+ Apartment::Migrator.should_receive(:migrate).exactly(db_names.length).times
49
+
50
+ @rake['apartment:migrate'].invoke
51
+ end
52
+ end
53
+
54
+ describe "#rollback" do
55
+ it "should rollback all dbs" do
56
+ db_names.each do |name|
57
+ Apartment::Migrator.should_receive(:rollback).with(name, anything)
58
+ end
59
+
60
+ @rake['apartment:rollback'].invoke
61
+ @rake['apartment:migrate'].invoke # migrate again so that our next test 'seed' can run (requires migrations to be complete)
62
+ end
63
+ end
64
+
65
+ describe "apartment:seed" do
66
+ it "should seed all databases" do
67
+ Apartment::Database.should_receive(:seed).exactly(db_names.length).times
68
+
69
+ @rake['apartment:seed'].invoke
70
+ end
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,200 @@
1
+ require 'spec_helper'
2
+
3
+ describe Apartment::Database do
4
+
5
+ context "using postgresql" do
6
+
7
+ # See apartment.yml file in dummy app config
8
+
9
+ let(:config){ Apartment::Test.config['connections']['postgresql'].symbolize_keys }
10
+ let(:database){ "some_new_database" }
11
+ let(:database2){ "yet_another_database" }
12
+
13
+ before do
14
+ Apartment.use_postgres_schemas = true
15
+ ActiveRecord::Base.establish_connection config
16
+ Apartment::Test.load_schema # load the Rails schema in the public db schema
17
+ Apartment::Database.stub(:config).and_return config # Use postgresql database config for this test
18
+ @schema_search_path = ActiveRecord::Base.connection.schema_search_path
19
+ end
20
+
21
+ after do
22
+ Apartment::Test.reset
23
+ end
24
+
25
+ describe "#init" do
26
+
27
+ it "should process model exclusions" do
28
+ Apartment.configure do |config|
29
+ config.excluded_models = ["Company"]
30
+ end
31
+
32
+ Apartment::Database.init
33
+
34
+ Company.table_name.should == "public.companies"
35
+ end
36
+
37
+ end
38
+
39
+ describe "#adapter" do
40
+ before do
41
+ Apartment::Database.reload!
42
+ end
43
+
44
+ it "should load postgresql adapter" do
45
+ Apartment::Database.adapter
46
+ Apartment::Adapters::PostgresqlAdapter.should be_a(Class)
47
+ end
48
+
49
+ it "should raise exception with invalid adapter specified" do
50
+ Apartment::Database.stub(:config).and_return config.merge(:adapter => 'unkown')
51
+
52
+ expect {
53
+ Apartment::Database.adapter
54
+ }.to raise_error
55
+ end
56
+
57
+ end
58
+
59
+ context "with schemas" do
60
+
61
+ before do
62
+ Apartment.configure do |config|
63
+ config.excluded_models = []
64
+ config.use_postgres_schemas = true
65
+ config.seed_after_create = true
66
+ end
67
+ Apartment::Database.create database
68
+ end
69
+
70
+ after do
71
+ Apartment::Test.drop_schema database
72
+ end
73
+
74
+ describe "#process" do
75
+
76
+ before do
77
+ Apartment::Database.create database2
78
+ end
79
+
80
+ after do
81
+ Apartment::Test.drop_schema database2
82
+ end
83
+
84
+ it "should connect to new schema" do
85
+ Apartment::Database.process(database) do
86
+ Apartment::Database.current_database.should == database
87
+ end
88
+ end
89
+
90
+ it "should reset connection to the previous db" do
91
+ Apartment::Database.switch(database2)
92
+ Apartment::Database.process(database)
93
+ Apartment::Database.current_database.should == database2
94
+ end
95
+
96
+ it "should reset to previous schema if database is nil" do
97
+ Apartment::Database.switch(database)
98
+ Apartment::Database.process
99
+ Apartment::Database.current_database.should == database
100
+ end
101
+
102
+ it "should set to public schema if database is nil" do
103
+ Apartment::Database.process do
104
+ Apartment::Database.current_database.should == @schema_search_path
105
+ end
106
+ end
107
+
108
+ end
109
+
110
+ describe "#create" do
111
+ it "should create new postgres schema" do
112
+ ActiveRecord::Base.connection.execute("SELECT nspname FROM pg_namespace;").collect{|row| row['nspname']}.should include(database)
113
+ end
114
+
115
+ it "should seed data" do
116
+ Apartment::Database.switch database
117
+ User.count.should be > 0
118
+ end
119
+ end
120
+
121
+ describe "#switch" do
122
+
123
+ let(:x){ rand(3) }
124
+
125
+ it "should connect to new schema" do
126
+ Apartment::Database.switch database
127
+ ActiveRecord::Base.connection.schema_search_path.should == database
128
+ end
129
+
130
+ it "should fail with invalid schema" do
131
+ expect {
132
+ Apartment::Database.switch('some_nonexistent_schema')
133
+ }.to raise_error Apartment::SchemaNotFound
134
+ end
135
+
136
+ context "creating models" do
137
+
138
+ before do
139
+ Apartment::Database.create database2
140
+ end
141
+
142
+ after do
143
+ Apartment::Test.drop_schema database2
144
+ end
145
+
146
+ it "should create a model instance in the current schema" do
147
+ Apartment::Database.switch database2
148
+ db2_count = User.count + x.times{ User.create }
149
+
150
+ Apartment::Database.switch database
151
+ db_count = User.count + x.times{ User.create }
152
+
153
+ Apartment::Database.switch database2
154
+ User.count.should == db2_count
155
+
156
+ Apartment::Database.switch database
157
+ User.count.should == db_count
158
+ end
159
+ end
160
+
161
+ context "with excluded models" do
162
+
163
+ before do
164
+ Apartment.configure do |config|
165
+ config.excluded_models = ["Company"]
166
+ end
167
+ Apartment::Database.init
168
+ end
169
+
170
+ it "should ignore excluded models" do
171
+ Apartment::Database.switch database
172
+ Company.table_name.should include('public')
173
+ end
174
+
175
+ it "should create excluded models in public schema" do
176
+ Apartment::Database.reset # ensure we're on public schema
177
+ count = Company.count + x.times{ Company.create }
178
+
179
+ Apartment::Database.switch database
180
+ x.times{ Company.create }
181
+ Company.count.should == count + x
182
+ Apartment::Database.reset
183
+ Company.count.should == count + x
184
+ end
185
+ end
186
+
187
+ end
188
+
189
+ describe "#current_database" do
190
+
191
+ it "should return the current schema search path" do
192
+ Apartment::Database.switch database
193
+ Apartment::Database.current_database.should == database
194
+ end
195
+ end
196
+
197
+ end
198
+
199
+ end
200
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+ require 'delayed_job'
3
+ Delayed::Worker.guess_backend
4
+
5
+ describe Apartment::Delayed do
6
+
7
+ # See apartment.yml file in dummy app config
8
+
9
+ let(:config){ Apartment::Test.config['connections']['postgresql'].symbolize_keys }
10
+ let(:database){ "some_new_database" }
11
+ let(:database2){ "another_db" }
12
+
13
+ before do
14
+ ActiveRecord::Base.establish_connection config
15
+ Apartment::Test.load_schema # load the Rails schema in the public db schema
16
+ Apartment::Database.stub(:config).and_return config # Use postgresql database config for this test
17
+ @schema_search_path = ActiveRecord::Base.connection.schema_search_path
18
+
19
+ Apartment.configure do |config|
20
+ config.use_postgres_schemas = true
21
+ end
22
+
23
+ Apartment::Database.create database
24
+ Apartment::Database.create database2
25
+ end
26
+
27
+ after do
28
+ Apartment::Test.drop_schema database
29
+ Apartment::Test.drop_schema database2
30
+ Apartment::Test.reset
31
+ end
32
+
33
+ describe Apartment::Delayed::Job do
34
+ context "#enqueue" do
35
+
36
+ before do
37
+ Apartment::Database.reset
38
+ end
39
+
40
+ it "should queue up jobs in the public schema" do
41
+ dj_count = Delayed::Job.count
42
+ Apartment::Database.switch database
43
+ Apartment::Delayed::Job.enqueue FakeDjClass.new
44
+ Apartment::Database.reset
45
+
46
+ Delayed::Job.count.should == dj_count + 1
47
+ end
48
+
49
+ it "should not queue jobs in the current schema" do
50
+ Apartment::Database.switch database
51
+ expect {
52
+ Apartment::Delayed::Job.enqueue FakeDjClass.new
53
+ }.to_not change(Delayed::Job, :count) # because we will still be on the `database` schema, not public
54
+ end
55
+ end
56
+ end
57
+
58
+ describe Apartment::Delayed::Requirements do
59
+
60
+ before do
61
+ Apartment::Database.switch database
62
+ User.send(:include, Apartment::Delayed::Requirements)
63
+ User.create
64
+ end
65
+
66
+ it "should initialize a database attribute on a class" do
67
+ user = User.first
68
+ user.database.should == database
69
+ end
70
+
71
+ it "should not overwrite any previous after_initialize declarations" do
72
+ User.class_eval do
73
+ after_find :set_name
74
+
75
+ def set_name
76
+ self.name = "Some Name"
77
+ end
78
+ end
79
+
80
+ user = User.first
81
+ user.database.should == database
82
+ user.name.should == "Some Name"
83
+ end
84
+
85
+ it "should set the db on a new record before it saves" do
86
+ user = User.create
87
+ user.database.should == database
88
+ end
89
+
90
+ context "serialization" do
91
+ it "should serialize the proper database attribute" do
92
+ user_yaml = User.first.to_yaml
93
+ Apartment::Database.switch database2
94
+ user = YAML.load user_yaml
95
+ user.database.should == database
96
+ end
97
+ end
98
+ end
99
+
100
+ end