dr-apartment 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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