mataki-subdomain_routes 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe "resource" do
4
+ describe "mappings" do
5
+ it "should pass the specified subdomains to any nested routes" do
6
+ map_subdomain(:admin) do |admin|
7
+ admin.resources(:users) { |user| user.options[:subdomains].should == [ "admin" ] }
8
+ admin.resource(:config) { |config| config.options[:subdomains].should == [ "admin" ] }
9
+ end
10
+ end
11
+ end
12
+
13
+ describe "routes" do
14
+ before(:each) do
15
+ map_subdomain(:admin) do |admin|
16
+ admin.resources :users
17
+ admin.resource :config
18
+ end
19
+ end
20
+
21
+ it "should include the subdomains in the routing conditions" do
22
+ ActionController::Routing::Routes.routes.each do |route|
23
+ route.conditions[:subdomains].should == [ "admin" ]
24
+ end
25
+ end
26
+
27
+ it "should include the subdomains in the routing requirements" do
28
+ ActionController::Routing::Routes.routes.each do |route|
29
+ route.requirements[:subdomains].should == [ "admin" ]
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ActionController::Routing::Routes" do
4
+ before(:each) do
5
+ map_subdomain(:www, nil) { |www| www.root :controller => "homes", :action => "show" }
6
+ end
7
+
8
+ it "should know a list of its reserved subdomains" do
9
+ ActionController::Routing::Routes.reserved_subdomains.should == [ "www", "" ]
10
+ ActionController::Routing::Routes.clear!
11
+ ActionController::Routing::Routes.reserved_subdomains.should be_empty
12
+ end
13
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec'
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ require 'rubygems'
5
+ require 'active_support'
6
+ require 'action_controller'
7
+ require 'active_record' # only required for testing optional features, not required by the gem
8
+ require 'action_mailer' # only required for testing optional features, not required by the gem
9
+
10
+ require 'subdomain_routes'
11
+
12
+ require 'action_controller/test_process'
13
+ require 'action_view/test_case'
14
+ require 'test_unit_matcher'
15
+
16
+ ActiveSupport::OptionMerger.send(:define_method, :options) { @options }
17
+
18
+
19
+ Spec::Runner.configure do |config|
20
+ config.before(:each) do
21
+ ActionController::Routing::Routes.clear!
22
+ SubdomainRoutes::Config.stub!(:domain_length).and_return(2)
23
+ end
24
+ config.include(SubdomainRoutes::TestUnitMatcher)
25
+ end
26
+
27
+ def map_subdomain(*subdomains, &block)
28
+ ActionController::Routing::Routes.draw do |map|
29
+ map.subdomain(*subdomains, &block)
30
+ end
31
+ end
32
+
33
+ def recognize_path(request)
34
+ ActionController::Routing::Routes.recognize_path(request.path, ActionController::Routing::Routes.extract_request_environment(request))
35
+ end
36
+
37
+ def in_controller_with_host(host, options = {}, &block)
38
+ spec = self
39
+ Class.new(ActionView::TestCase::TestController) do
40
+ include Spec::Matchers
41
+ end.new.instance_eval do
42
+ request.host = host
43
+ request.instance_eval do
44
+ @env.merge! 'HTTPS' => 'on','SERVER_PORT' => 443 if options[:protocol] =~ /^https(:\/\/)?$/
45
+ @env.merge! 'SERVER_PORT'=> options[:port] if options[:port]
46
+ end
47
+ copy_instance_variables_from(spec)
48
+ instance_eval(&block)
49
+ end
50
+ end
51
+
52
+ def in_object_with_host(host, options = {}, &block)
53
+ spec = self
54
+ Class.new do
55
+ include Spec::Matchers
56
+ include ActionController::UrlWriter
57
+ end.new.instance_eval do
58
+ self.class.default_url_options = { :host => host }
59
+ self.class.default_url_options.merge! options.slice(:port, :protocol)
60
+ copy_instance_variables_from(spec)
61
+ instance_eval(&block)
62
+ end
63
+ end
64
+
65
+ def with_host(host, options = {}, &block)
66
+ in_controller_with_host(host, options.dup, &block)
67
+ in_object_with_host(host, options.dup, &block)
68
+ end
69
+
70
+ ActiveRecord::Base.class_eval do
71
+ alias_method :save, :valid?
72
+ def self.columns() @columns ||= []; end
73
+
74
+ def self.column(name, sql_type = nil, default = nil, null = true)
75
+ columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type, null)
76
+ end
77
+ end
@@ -0,0 +1,46 @@
1
+ module SubdomainRoutes
2
+ module TestUnitMatcher
3
+ class Base
4
+ class TestCase < ActionController::TestCase
5
+ end
6
+
7
+ def initialize(count_method, messages, spec)
8
+ @count_method, @messages, @spec = count_method, messages, spec
9
+ end
10
+
11
+ def run_test(target)
12
+ result = Test::Unit::TestResult.new
13
+ spec = @spec
14
+ TestCase.send :define_method, :test do
15
+ copy_instance_variables_from(spec)
16
+ instance_eval(&target)
17
+ end
18
+ TestCase.new(:test).run(result) {}
19
+ result
20
+ end
21
+
22
+ def matches?(target)
23
+ @result = run_test(target)
24
+ @result_count = @result.send(@count_method)
25
+ @result_count > 0
26
+ end
27
+
28
+ def failure_message
29
+ "Expected #{@count_method.to_s.humanize.downcase} to be more than zero, got zero.\n"
30
+ end
31
+
32
+ def negative_failure_message
33
+ "Expected #{@count_method.to_s.humanize.downcase} to be zero, got #{@result_count}:\n" +
34
+ @result.instance_variable_get(@messages).map(&:inspect).join("\n")
35
+ end
36
+ end
37
+
38
+ def have_errors
39
+ Base.new(:error_count, :@errors, self)
40
+ end
41
+
42
+ def fail
43
+ Base.new(:failure_count, :@failures, self)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,262 @@
1
+ require 'spec_helper'
2
+
3
+ describe "URL writing" do
4
+ { "nil" => nil, "an IP address" => "207.192.69.152" }.each do |host_type, host|
5
+ context "when the host is #{host_type}" do
6
+ it "should raise an error when a subdomain route is requested" do
7
+ map_subdomain(:www) { |www| www.resources :users }
8
+ with_host(host) do
9
+ lambda { www_users_path }.should raise_error(SubdomainRoutes::HostNotSupplied)
10
+ lambda { url_for(:controller => "users", :action => "index", :subdomains => ["www"]) }.should raise_error(SubdomainRoutes::HostNotSupplied)
11
+ end
12
+ end
13
+
14
+ context "and a non-subdomain route is requested" do
15
+ before(:each) do
16
+ ActionController::Routing::Routes.draw { |map| map.resources :users }
17
+ end
18
+
19
+ it "should not raise an error when the route is a path" do
20
+ with_host(host) do
21
+ lambda { users_path }.should_not raise_error
22
+ lambda { url_for(:controller => "users", :action => "index", :only_path => true) }.should_not raise_error
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ [ [ "single", :admin, "admin.example.com" ],
30
+ [ "nil", nil, "example.com" ] ].each do |type, subdomain, host|
31
+ context "when a #{type} subdomain is specified" do
32
+ before(:each) do
33
+ map_subdomain(subdomain, :name => nil) { |map| map.resources :users }
34
+ @url_options = { :controller => "users", :action => "index", :subdomains => [ subdomain.to_s ] }
35
+ @path_options = @url_options.merge(:only_path => true)
36
+ end
37
+
38
+ it "should not change the host for an URL if the host subdomain matches" do
39
+ with_host(host) do
40
+ users_url.should == "http://#{host}/users"
41
+ url_for(@url_options).should == "http://#{host}/users"
42
+ end
43
+ end
44
+
45
+ it "should change the host for an URL if the host subdomain differs" do
46
+ with_host "other.example.com" do
47
+ users_url.should == "http://#{host}/users"
48
+ url_for(@url_options).should == "http://#{host}/users"
49
+ end
50
+ end
51
+
52
+ it "should not force the host for a path if the host subdomain matches" do
53
+ with_host(host) do
54
+ users_path.should == "/users"
55
+ url_for(@path_options).should == "/users"
56
+ end
57
+ end
58
+
59
+ it "should force the host for a path if the host subdomain differs" do
60
+ with_host "other.example.com" do
61
+ users_path.should == "http://#{host}/users"
62
+ url_for(@path_options).should == "http://#{host}/users"
63
+ end
64
+ end
65
+
66
+ [ [ "port", { :port => 8080 }, "http://#{host}:8080/users" ],
67
+ [ "protocol", { :protocol => "https" }, "https://#{host}/users" ] ].each do |variant, options, url|
68
+ it "should preserve the #{variant} when forcing the host" do
69
+ with_host "other.example.com", options do
70
+ users_path.should == url
71
+ url_for(@path_options).should == url
72
+ end
73
+ end
74
+ end
75
+
76
+ context "and a subdomain different from the host subdomain is explicitly requested" do
77
+ it "should change the host if the requested subdomain matches" do
78
+ with_host "other.example.com" do
79
+ users_path(:subdomain => subdomain).should == "http://#{host}/users"
80
+ url_for(@path_options.merge(:subdomain => subdomain)).should == "http://#{host}/users"
81
+ end
82
+ end
83
+
84
+ it "should raise a routing error if the requested subdomain doesn't match" do
85
+ with_host(host) do
86
+ lambda { users_path(:subdomain => :other) }.should raise_error(ActionController::RoutingError)
87
+ lambda { url_for(@path_options.merge(:subdomain => :other)) }.should raise_error(ActionController::RoutingError)
88
+ end
89
+ end
90
+ end
91
+
92
+ context "and the current host's subdomain is explicitly requested" do
93
+ it "should not force the host for a path if the subdomain matches" do
94
+ with_host(host) do
95
+ users_path(:subdomain => subdomain).should == "/users"
96
+ url_for(@path_options.merge(:subdomain => subdomain)).should == "/users"
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ [ [ "", [ :books, :dvds ], [ "books.example.com", "dvds.example.com" ] ],
104
+ [ " including nil", [ nil, :www ], [ "example.com", "www.example.com" ] ] ].each do |qualifier, subdomains, hosts|
105
+ context "when multiple subdomains#{qualifier} are specified" do
106
+ before(:each) do
107
+ args = subdomains + [ :name => nil ]
108
+ map_subdomain(*args) { |map| map.resources :items }
109
+ @url_options = { :controller => "items", :action => "index", :subdomains => subdomains.map(&:to_s) }
110
+ @path_options = @url_options.merge(:only_path => true)
111
+ end
112
+
113
+ it "should not change the host for an URL if the host subdomain matches" do
114
+ hosts.each do |host|
115
+ with_host(host) do
116
+ items_url.should == "http://#{host}/items"
117
+ url_for(@url_options).should == "http://#{host}/items"
118
+ end
119
+ end
120
+ end
121
+
122
+ it "should not force the host for a path if the host subdomain matches" do
123
+ hosts.each do |host|
124
+ with_host(host) do
125
+ items_path.should == "/items"
126
+ url_for(@path_options).should == "/items"
127
+ end
128
+ end
129
+ end
130
+
131
+ it "should raise a routing error if the host subdomain doesn't match" do
132
+ with_host "other.example.com" do
133
+ lambda { item_url }.should raise_error(ActionController::RoutingError)
134
+ lambda { item_path }.should raise_error(ActionController::RoutingError)
135
+ lambda { url_for(@url_options) }.should raise_error(ActionController::RoutingError)
136
+ lambda { url_for(@path_options) }.should raise_error(ActionController::RoutingError)
137
+ end
138
+ end
139
+
140
+ context "and a subdomain different from the host subdomain is explicitly requested" do
141
+ it "should change the host if the requested subdomain matches" do
142
+ [ [ subdomains.first, hosts.first, hosts.last ],
143
+ [ subdomains.last, hosts.last, hosts.first ] ].each do |subdomain, new_host, old_host|
144
+ with_host(old_host) do
145
+ items_path(:subdomain => subdomain).should == "http://#{new_host}/items"
146
+ url_for(@path_options.merge(:subdomain => subdomain)).should == "http://#{new_host}/items"
147
+ end
148
+ end
149
+ end
150
+
151
+ it "should preserve the port when changing the host" do
152
+ [ [ subdomains.first, hosts.first, hosts.last ],
153
+ [ subdomains.last, hosts.last, hosts.first ] ].each do |subdomain, new_host, old_host|
154
+ with_host(old_host, :port => 8080) do
155
+ items_path(:subdomain => subdomain).should == "http://#{new_host}:8080/items"
156
+ url_for(@path_options.merge(:subdomain => subdomain)).should == "http://#{new_host}:8080/items"
157
+ end
158
+ end
159
+ end
160
+
161
+ it "should preserve the protocol when changing the host" do
162
+ [ [ subdomains.first, hosts.first, hosts.last ],
163
+ [ subdomains.last, hosts.last, hosts.first ] ].each do |subdomain, new_host, old_host|
164
+ with_host(old_host, :protocol => "https") do
165
+ items_path(:subdomain => subdomain).should == "https://#{new_host}/items"
166
+ url_for(@path_options.merge(:subdomain => subdomain)).should == "https://#{new_host}/items"
167
+ end
168
+ end
169
+ end
170
+
171
+ it "should raise a routing error if the requested subdomain doesn't match" do
172
+ [ [ hosts.first, hosts.last ],
173
+ [ hosts.last, hosts.first ] ].each do |new_host, old_host|
174
+ with_host(old_host) do
175
+ lambda { items_path(:subdomain => :other) }.should raise_error(ActionController::RoutingError)
176
+ lambda { url_for(@path_options.merge(:subdomain => :other)) }.should raise_error(ActionController::RoutingError)
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ it "should downcase a supplied subdomain" do
185
+ map_subdomain(:www1, :www2, :name => nil) { |map| map.resources :users }
186
+ [ [ :Www1, "www1" ], [ "Www2", "www2" ] ].each do |mixedcase, lowercase|
187
+ with_host "www.example.com" do
188
+ users_url(:subdomain => mixedcase).should == "http://#{lowercase}.example.com/users"
189
+ url_for(:controller => "users", :action => "index", :subdomains => [ "www1", "www2" ], :subdomain => mixedcase).should == "http://#{lowercase}.example.com/users"
190
+ end
191
+ end
192
+ end
193
+
194
+ context "when a :model subdomain is specified" do
195
+ before(:each) do
196
+ map_subdomain(:model => :city) { |city| city.resources :events }
197
+ class City < ActiveRecord::Base; end
198
+ @boston = City.new
199
+ @boston.stub!(:new_record?).and_return(false)
200
+ @boston.stub!(:to_param).and_return("boston")
201
+ @url_options = { :controller => "city/events", :action => "index", :subdomains => :city_id, :city_id => @boston }
202
+ @path_options = @url_options.merge(:only_path => true)
203
+ end
204
+
205
+ it "should not change the host if the object has the same to_param as the current subdomain" do
206
+ with_host "boston.example.com" do
207
+ city_events_url(@boston).should == "http://boston.example.com/events"
208
+ city_events_path(@boston).should == "/events"
209
+ url_for(@url_options).should == "http://boston.example.com/events"
210
+ url_for(@path_options).should == "/events"
211
+ end
212
+ end
213
+
214
+ it "should force the host if the object has a different to_param from the current subdomain" do
215
+ with_host "example.com" do
216
+ city_events_url(@boston).should == "http://boston.example.com/events"
217
+ city_events_path(@boston).should == "http://boston.example.com/events"
218
+ url_for(@url_options).should == "http://boston.example.com/events"
219
+ url_for(@path_options).should == "http://boston.example.com/events"
220
+ end
221
+ end
222
+
223
+ [ [ "port", { :port => 8080 }, "http://boston.example.com:8080/events" ],
224
+ [ "protocol", { :protocol => "https" }, "https://boston.example.com/events" ] ].each do |variant, options, url|
225
+ it "should preserve the #{variant} when forcing the host" do
226
+ with_host "example.com", options do
227
+ city_events_url(@boston).should == url
228
+ city_events_path(@boston).should == url
229
+ url_for(@url_options).should == url
230
+ url_for(@path_options).should == url
231
+ end
232
+ end
233
+ end
234
+
235
+ it "should raise an error if the object to_param is an invalid subdomain" do
236
+ @newyork = City.new
237
+ @newyork.stub!(:new_record?).and_return(false)
238
+ @newyork.stub!(:to_param).and_return("new york")
239
+ with_host "www.example.com" do
240
+ lambda { city_events_url(@newyork) }.should raise_error(ActionController::RoutingError)
241
+ lambda { city_events_path(@newyork) }.should raise_error(ActionController::RoutingError)
242
+ lambda { url_for(@url_options.merge(:city_id => @newyork)) }.should raise_error(ActionController::RoutingError)
243
+ lambda { url_for(@path_options.merge(:city_id => @newyork)) }.should raise_error(ActionController::RoutingError)
244
+ end
245
+ end
246
+
247
+ it "should not allow the subdomain to be manually overridden in a named route" do
248
+ with_host "www.example.com" do
249
+ city_events_url(@boston, :subdomain => :canberra).should == "http://boston.example.com/events"
250
+ city_events_path(@boston, :subdomain => :canberra).should == "http://boston.example.com/events"
251
+ end
252
+ end
253
+
254
+ it "should raise a routing error if no subdomain object is supplied to the named route" do
255
+ with_host "www.example.com" do
256
+ [ lambda { city_events_url }, lambda { city_event_url("id") } ].each do |lamb|
257
+ lamb.should raise_error(ActionController::RoutingError) { |e| e.message.should include(":city_id") }
258
+ end
259
+ end
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,27 @@
1
+ describe "ActiveRecord::Base" do
2
+ before(:each) do
3
+ class User < ActiveRecord::Base
4
+ attr_accessor :subdomain
5
+ end
6
+ end
7
+
8
+ it "should have validates_subdomain_format_of which runs SubdomainRoutes.valid_subdomain? against the attributes" do
9
+ User.validates_subdomain_format_of :subdomain
10
+ SubdomainRoutes.should_receive(:valid_subdomain?).with("mholling").and_return(true)
11
+ User.new(:subdomain => "mholling").should be_valid
12
+ SubdomainRoutes.should_receive(:valid_subdomain?).with("mholling").and_return(nil)
13
+ User.new(:subdomain => "mholling").should_not be_valid
14
+ end
15
+
16
+ it "should have validates_subdomain_not_reserved which checks the attributes against the fixed-subdomain routes" do
17
+ User.validates_subdomain_not_reserved :subdomain
18
+ reserved = [ "", "www", "support", "admin" ]
19
+ map_subdomain(*reserved) { |map| map.resource :home }
20
+ reserved.each do |subdomain|
21
+ User.new(:subdomain => subdomain).should_not be_valid
22
+ end
23
+ [ "mholling", "edmondst" ].each do |subdomain|
24
+ User.new(:subdomain => subdomain).should be_valid
25
+ end
26
+ end
27
+ end