tennpipes-base 3.6.6
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.
- checksums.yaml +7 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +294 -0
- data/Rakefile +1 -0
- data/bin/tennpipes +8 -0
- data/lib/tennpipes-base.rb +196 -0
- data/lib/tennpipes-base/application.rb +175 -0
- data/lib/tennpipes-base/application/application_setup.rb +202 -0
- data/lib/tennpipes-base/application/authenticity_token.rb +25 -0
- data/lib/tennpipes-base/application/flash.rb +229 -0
- data/lib/tennpipes-base/application/params_protection.rb +129 -0
- data/lib/tennpipes-base/application/routing.rb +1002 -0
- data/lib/tennpipes-base/application/show_exceptions.rb +50 -0
- data/lib/tennpipes-base/caller.rb +53 -0
- data/lib/tennpipes-base/cli/adapter.rb +33 -0
- data/lib/tennpipes-base/cli/base.rb +105 -0
- data/lib/tennpipes-base/cli/console.rb +20 -0
- data/lib/tennpipes-base/cli/launcher.rb +103 -0
- data/lib/tennpipes-base/cli/rake.rb +50 -0
- data/lib/tennpipes-base/cli/rake_tasks.rb +72 -0
- data/lib/tennpipes-base/command.rb +38 -0
- data/lib/tennpipes-base/ext/sinatra.rb +29 -0
- data/lib/tennpipes-base/filter.rb +52 -0
- data/lib/tennpipes-base/images/404.png +0 -0
- data/lib/tennpipes-base/images/500.png +0 -0
- data/lib/tennpipes-base/loader.rb +202 -0
- data/lib/tennpipes-base/logger.rb +492 -0
- data/lib/tennpipes-base/module.rb +58 -0
- data/lib/tennpipes-base/mounter.rb +308 -0
- data/lib/tennpipes-base/path_router.rb +119 -0
- data/lib/tennpipes-base/path_router/compiler.rb +110 -0
- data/lib/tennpipes-base/path_router/error_handler.rb +8 -0
- data/lib/tennpipes-base/path_router/matcher.rb +123 -0
- data/lib/tennpipes-base/path_router/route.rb +169 -0
- data/lib/tennpipes-base/reloader.rb +309 -0
- data/lib/tennpipes-base/reloader/rack.rb +26 -0
- data/lib/tennpipes-base/reloader/storage.rb +55 -0
- data/lib/tennpipes-base/router.rb +98 -0
- data/lib/tennpipes-base/server.rb +119 -0
- data/lib/tennpipes-base/tasks.rb +21 -0
- data/lib/tennpipes-base/version.rb +20 -0
- data/lib/tennpipes-base/version.rb~ +20 -0
- data/test/fixtures/app_gem/Gemfile +4 -0
- data/test/fixtures/app_gem/app/app.rb +3 -0
- data/test/fixtures/app_gem/app_gem.gemspec +17 -0
- data/test/fixtures/app_gem/lib/app_gem.rb +7 -0
- data/test/fixtures/app_gem/lib/app_gem/version.rb +3 -0
- data/test/fixtures/apps/complex.rb +32 -0
- data/test/fixtures/apps/demo_app.rb +7 -0
- data/test/fixtures/apps/demo_demo.rb +7 -0
- data/test/fixtures/apps/demo_project/api/app.rb +7 -0
- data/test/fixtures/apps/demo_project/api/lib/api_lib.rb +3 -0
- data/test/fixtures/apps/demo_project/app.rb +7 -0
- data/test/fixtures/apps/external_apps/fake_lib.rb +1 -0
- data/test/fixtures/apps/external_apps/fake_root.rb +2 -0
- data/test/fixtures/apps/helpers/class_methods_helpers.rb +4 -0
- data/test/fixtures/apps/helpers/instance_methods_helpers.rb +4 -0
- data/test/fixtures/apps/helpers/support.rb +1 -0
- data/test/fixtures/apps/helpers/system_helpers.rb +8 -0
- data/test/fixtures/apps/kiq.rb +3 -0
- data/test/fixtures/apps/lib/myklass.rb +2 -0
- data/test/fixtures/apps/lib/myklass/mysubklass.rb +4 -0
- data/test/fixtures/apps/models/child.rb +2 -0
- data/test/fixtures/apps/models/parent.rb +5 -0
- data/test/fixtures/apps/mountable_apps/rack_apps.rb +15 -0
- data/test/fixtures/apps/mountable_apps/static.html +1 -0
- data/test/fixtures/apps/precompiled_app.rb +19 -0
- data/test/fixtures/apps/simple.rb +32 -0
- data/test/fixtures/apps/static.rb +10 -0
- data/test/fixtures/apps/system.rb +13 -0
- data/test/fixtures/apps/system_class_methods_demo.rb +7 -0
- data/test/fixtures/apps/system_instance_methods_demo.rb +7 -0
- data/test/fixtures/dependencies/a.rb +9 -0
- data/test/fixtures/dependencies/b.rb +4 -0
- data/test/fixtures/dependencies/c.rb +1 -0
- data/test/fixtures/dependencies/circular/e.rb +13 -0
- data/test/fixtures/dependencies/circular/f.rb +2 -0
- data/test/fixtures/dependencies/circular/g.rb +2 -0
- data/test/fixtures/dependencies/d.rb +4 -0
- data/test/fixtures/reloadable_apps/external/app/app.rb +6 -0
- data/test/fixtures/reloadable_apps/external/app/controllers/base.rb +6 -0
- data/test/fixtures/reloadable_apps/main/app.rb +10 -0
- data/test/helper.rb +30 -0
- data/test/test_application.rb +185 -0
- data/test/test_core.rb +93 -0
- data/test/test_csrf_protection.rb +208 -0
- data/test/test_dependencies.rb +57 -0
- data/test/test_filters.rb +389 -0
- data/test/test_flash.rb +168 -0
- data/test/test_locale.rb +21 -0
- data/test/test_logger.rb +295 -0
- data/test/test_mounter.rb +302 -0
- data/test/test_params_protection.rb +195 -0
- data/test/test_reloader_complex.rb +74 -0
- data/test/test_reloader_external.rb +21 -0
- data/test/test_reloader_simple.rb +101 -0
- data/test/test_reloader_system.rb +113 -0
- data/test/test_restful_routing.rb +33 -0
- data/test/test_router.rb +281 -0
- data/test/test_routing.rb +2328 -0
- metadata +301 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/fixtures/apps/complex')
|
|
3
|
+
|
|
4
|
+
describe "ComplexReloader" do
|
|
5
|
+
|
|
6
|
+
describe 'for complex reload functionality' do
|
|
7
|
+
before do
|
|
8
|
+
Tennpipes.clear!
|
|
9
|
+
Tennpipes.mount("complex_1_demo").to("/complex_1_demo")
|
|
10
|
+
Tennpipes.mount("complex_2_demo").to("/complex_2_demo")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'should correctly instantiate Complex(1-2)Demo fixture' do
|
|
14
|
+
assert_equal ["/complex_1_demo", "/complex_2_demo"], Tennpipes.mounted_apps.map(&:uri_root)
|
|
15
|
+
assert_equal ["complex_1_demo", "complex_2_demo"], Tennpipes.mounted_apps.map(&:name)
|
|
16
|
+
assert Complex1Demo.reload?
|
|
17
|
+
assert Complex2Demo.reload?
|
|
18
|
+
assert_match %r{fixtures/apps/complex.rb}, Complex1Demo.app_file
|
|
19
|
+
assert_match %r{fixtures/apps/complex.rb}, Complex2Demo.app_file
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'should correctly reload Complex(1-2)Demo fixture' do
|
|
23
|
+
assert_match %r{fixtures/apps/complex.rb}, Complex1Demo.app_file
|
|
24
|
+
@app = Tennpipes.application
|
|
25
|
+
|
|
26
|
+
get "/"
|
|
27
|
+
assert_equal 404, status
|
|
28
|
+
|
|
29
|
+
get "/complex_1_demo"
|
|
30
|
+
assert_equal "Given random #{LibDemo.give_me_a_random}", body
|
|
31
|
+
|
|
32
|
+
get "/complex_2_demo"
|
|
33
|
+
assert_equal 200, status
|
|
34
|
+
|
|
35
|
+
get "/complex_1_demo/old"
|
|
36
|
+
assert_equal 200, status
|
|
37
|
+
|
|
38
|
+
get "/complex_2_demo/old"
|
|
39
|
+
assert_equal 200, status
|
|
40
|
+
|
|
41
|
+
get "/complex_2_demo/var/destroy"
|
|
42
|
+
assert_equal '{}', body
|
|
43
|
+
|
|
44
|
+
new_phrase = "The magick number is: #{rand(2**255)}!"
|
|
45
|
+
buffer = File.read(Complex1Demo.app_file)
|
|
46
|
+
new_buffer = buffer.sub(/The magick number is: \d+!/, new_phrase)
|
|
47
|
+
new_buffer.sub!(/get\(:destroy\)/, 'get(:destroy, :with => :id)')
|
|
48
|
+
begin
|
|
49
|
+
File.open(Complex1Demo.app_file, "w") { |f| f.write(new_buffer) }
|
|
50
|
+
Time.stub(:now, Time.now + 2) { get "/complex_2_demo" }
|
|
51
|
+
assert_equal new_phrase, body
|
|
52
|
+
|
|
53
|
+
# Re-Check that we didn't forget any route
|
|
54
|
+
get "/complex_1_demo"
|
|
55
|
+
assert_equal "Given random #{LibDemo.give_me_a_random}", body
|
|
56
|
+
|
|
57
|
+
get "/complex_2_demo"
|
|
58
|
+
assert_equal 200, status
|
|
59
|
+
|
|
60
|
+
get "/complex_1_demo/old"
|
|
61
|
+
assert_equal 200, status
|
|
62
|
+
|
|
63
|
+
get "/complex_2_demo/old"
|
|
64
|
+
assert_equal 200, status
|
|
65
|
+
|
|
66
|
+
get "/complex_2_demo/var/destroy/variable"
|
|
67
|
+
assert_equal '{"id"=>"variable"}', body
|
|
68
|
+
ensure
|
|
69
|
+
# Now we need to prevent to commit a new changed file so we revert it
|
|
70
|
+
File.open(Complex1Demo.app_file, "w") { |f| f.write(buffer) }
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/fixtures/reloadable_apps/main/app')
|
|
3
|
+
|
|
4
|
+
describe "ExternalReloader" do
|
|
5
|
+
describe "for external app" do
|
|
6
|
+
before do
|
|
7
|
+
Tennpipes.clear!
|
|
8
|
+
Tennpipes.mount("ReloadableApp::External").to("/reloadable/external")
|
|
9
|
+
Tennpipes.mount("ReloadableApp::Main").to("/reloadable")
|
|
10
|
+
Tennpipes.load!
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should avoid reloading the file if its path is not started with Tennpipes.root" do
|
|
14
|
+
@app = Tennpipes.application
|
|
15
|
+
Tennpipes.stub(:root, File.expand_path(File.dirname(__FILE__) + '/fixtures/reloadable_apps/main')) do
|
|
16
|
+
get "/reloadable/external/base"
|
|
17
|
+
end
|
|
18
|
+
assert_equal "Hello External App", body
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/fixtures/apps/simple')
|
|
3
|
+
|
|
4
|
+
describe "SimpleReloader" do
|
|
5
|
+
|
|
6
|
+
describe 'for simple reset functionality' do
|
|
7
|
+
|
|
8
|
+
it 'should reset routes' do
|
|
9
|
+
mock_app do
|
|
10
|
+
(1..10).each do |i|
|
|
11
|
+
get("/#{i}") { "Foo #{i}" }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
(1..10).each do |i|
|
|
15
|
+
get "/#{i}"
|
|
16
|
+
assert_equal "Foo #{i}", body
|
|
17
|
+
end
|
|
18
|
+
@app.reset_routes!
|
|
19
|
+
(1..10).each do |i|
|
|
20
|
+
get "/#{i}"
|
|
21
|
+
assert_equal 404, status
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'should keep sinatra routes on development' do
|
|
26
|
+
mock_app do
|
|
27
|
+
set :environment, :development
|
|
28
|
+
get("/"){ "ok" }
|
|
29
|
+
end
|
|
30
|
+
assert_equal :development, @app.environment
|
|
31
|
+
get "/"
|
|
32
|
+
assert_equal 200, status
|
|
33
|
+
get "/__sinatra__/404.png"
|
|
34
|
+
assert_equal 200, status
|
|
35
|
+
assert_match /image\/png/, response["Content-Type"]
|
|
36
|
+
@app.reset_routes!
|
|
37
|
+
get "/"
|
|
38
|
+
assert_equal 404, status
|
|
39
|
+
get "/__sinatra__/404.png"
|
|
40
|
+
assert_equal 200, status
|
|
41
|
+
assert_match /image\/png/, response["Content-Type"]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe 'for simple reload functionality' do
|
|
46
|
+
before do
|
|
47
|
+
Tennpipes.clear!
|
|
48
|
+
Tennpipes.mount("simple_demo").to("/")
|
|
49
|
+
Tennpipes.reload!
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'should correctly instantiate SimpleDemo fixture' do
|
|
53
|
+
assert_equal ["simple_demo"], Tennpipes.mounted_apps.map(&:name)
|
|
54
|
+
assert SimpleDemo.reload?
|
|
55
|
+
assert_match %r{fixtures/apps/simple.rb}, SimpleDemo.app_file
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'should correctly reload SimpleDemo fixture' do
|
|
59
|
+
@app = SimpleDemo
|
|
60
|
+
get "/"
|
|
61
|
+
assert ok?
|
|
62
|
+
new_phrase = "The magick number is: #{rand(2**255)}!"
|
|
63
|
+
buffer = File.read(SimpleDemo.app_file)
|
|
64
|
+
new_buffer = buffer.sub(/The magick number is: \d+!/, new_phrase)
|
|
65
|
+
begin
|
|
66
|
+
File.open(SimpleDemo.app_file, "w") { |f| f.write(new_buffer) }
|
|
67
|
+
Time.stub(:now, Time.now + 2) { get "/" }
|
|
68
|
+
assert_equal new_phrase, body
|
|
69
|
+
ensure
|
|
70
|
+
File.open(SimpleDemo.app_file, "w") { |f| f.write(buffer) }
|
|
71
|
+
Tennpipes.reload!
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'should correctly reset SimpleDemo fixture' do
|
|
76
|
+
@app = SimpleDemo
|
|
77
|
+
get "/"
|
|
78
|
+
@app.reload!
|
|
79
|
+
get "/rand"
|
|
80
|
+
assert ok?
|
|
81
|
+
last_body = body
|
|
82
|
+
assert_equal 1, @app.filters[:before].size
|
|
83
|
+
assert_equal 1, @app.errors.size
|
|
84
|
+
assert_equal 2, @app.filters[:after].size # app + content-type + tennpipes-flash
|
|
85
|
+
assert_equal 0, @app.middleware.size
|
|
86
|
+
assert_equal 4, @app.routes.size # GET+HEAD of "/" + GET+HEAD of "/rand" = 4
|
|
87
|
+
assert_equal 4, @app.extensions.size # [Tennpipes::ApplicationSetup, Tennpipes::ParamsProtection, Tennpipes::Routing, Tennpipes::Flash]
|
|
88
|
+
assert_equal 0, @app.templates.size
|
|
89
|
+
@app.reload!
|
|
90
|
+
get "/rand"
|
|
91
|
+
refute_equal last_body, body
|
|
92
|
+
assert_equal 1, @app.filters[:before].size
|
|
93
|
+
assert_equal 1, @app.errors.size
|
|
94
|
+
assert_equal 2, @app.filters[:after].size
|
|
95
|
+
assert_equal 0, @app.middleware.size
|
|
96
|
+
assert_equal 4, @app.routes.size # GET+HEAD of "/" = 2
|
|
97
|
+
assert_equal 4, @app.extensions.size # [Tennpipes::ApplicationSetup, Tennpipes::ParamsProtection, Tennpipes::Routing, Tennpipes::Flash]
|
|
98
|
+
assert_equal 0, @app.templates.size
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/fixtures/apps/kiq')
|
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/fixtures/apps/system')
|
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/fixtures/apps/static')
|
|
5
|
+
|
|
6
|
+
describe "SystemReloader" do
|
|
7
|
+
describe 'for wierd and difficult reload events' do
|
|
8
|
+
before do
|
|
9
|
+
@app = SystemDemo
|
|
10
|
+
get '/'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'should reload system features if they were required only in helper' do
|
|
14
|
+
@app.reload!
|
|
15
|
+
get '/'
|
|
16
|
+
assert_equal 'Resolv', body
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'should reload children on parent change' do
|
|
20
|
+
Tennpipes.mount(SystemDemo).to("/")
|
|
21
|
+
assert_equal Child.new.family, 'Danes'
|
|
22
|
+
parent_file = File.expand_path(File.dirname(__FILE__) + '/fixtures/apps/models/parent.rb')
|
|
23
|
+
new_class = <<-DOC
|
|
24
|
+
class Parent
|
|
25
|
+
def family
|
|
26
|
+
'Dancy'
|
|
27
|
+
end
|
|
28
|
+
def shmamily
|
|
29
|
+
'Shmancy'
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
DOC
|
|
33
|
+
begin
|
|
34
|
+
backup = File.read(parent_file)
|
|
35
|
+
Tennpipes::Reloader.reload!
|
|
36
|
+
assert_equal 'Danes', Parent.new.family
|
|
37
|
+
assert_equal 'Danes', Child.new.family
|
|
38
|
+
File.open(parent_file, "w") { |f| f.write(new_class) }
|
|
39
|
+
Tennpipes::Reloader.reload!
|
|
40
|
+
assert_equal 'Dancy', Parent.new.family
|
|
41
|
+
assert_equal 'Shmancy', Parent.new.shmamily
|
|
42
|
+
assert_equal 'Dancy', Child.new.family
|
|
43
|
+
assert_equal 'Shmancy', Child.new.shmamily
|
|
44
|
+
ensure
|
|
45
|
+
File.open(parent_file, "w") { |f| f.write(backup) }
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'should not fail horribly on reload event with non-tennpipes apps' do
|
|
50
|
+
Tennpipes.mount("kiq").to("/")
|
|
51
|
+
Tennpipes.reload!
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'should not reload apps with disabled reload' do
|
|
55
|
+
Tennpipes.mount(StaticDemo).to("/")
|
|
56
|
+
Tennpipes.reload!
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe 'reloading external constants' do
|
|
61
|
+
it 'should not touch external constants defining singleton methods' do
|
|
62
|
+
new_class = <<-DOC
|
|
63
|
+
class SingletonClassTest
|
|
64
|
+
def self.external_test
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
DOC
|
|
68
|
+
tmp_file = '/tmp/tennpipes_class_demo.rb'
|
|
69
|
+
begin
|
|
70
|
+
File.open(tmp_file, "w") { |f| f.write(new_class) }
|
|
71
|
+
Tennpipes.clear!
|
|
72
|
+
require File.expand_path(File.dirname(__FILE__) + '/fixtures/apps/system_class_methods_demo.rb')
|
|
73
|
+
@app = SystemClassMethodsDemo
|
|
74
|
+
Tennpipes.mount(SystemClassMethodsDemo).to("/")
|
|
75
|
+
get '/'
|
|
76
|
+
assert defined?(SingletonClassTest), 'SingletonClassTest undefined'
|
|
77
|
+
assert_includes SingletonClassTest.singleton_methods, :external_test
|
|
78
|
+
FileUtils.touch File.expand_path(File.dirname(__FILE__) + '/fixtures/apps/helpers/class_methods_helpers.rb')
|
|
79
|
+
Tennpipes.reload!
|
|
80
|
+
assert defined?(SingletonClassTest), 'SingletonClassTest undefined'
|
|
81
|
+
assert_includes SingletonClassTest.singleton_methods, :external_test
|
|
82
|
+
ensure
|
|
83
|
+
FileUtils.rm tmp_file
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'should not touch external constants defining instance methods' do
|
|
88
|
+
new_class = <<-DOC
|
|
89
|
+
class InstanceTest
|
|
90
|
+
def instance_test
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
DOC
|
|
94
|
+
tmp_file = '/tmp/tennpipes_instance_demo.rb'
|
|
95
|
+
begin
|
|
96
|
+
File.open(tmp_file, "w") { |f| f.write(new_class) }
|
|
97
|
+
Tennpipes.clear!
|
|
98
|
+
require File.expand_path(File.dirname(__FILE__) + '/fixtures/apps/system_instance_methods_demo.rb')
|
|
99
|
+
@app = SystemInstanceMethodsDemo
|
|
100
|
+
Tennpipes.mount(SystemInstanceMethodsDemo).to("/")
|
|
101
|
+
get '/'
|
|
102
|
+
assert defined?(InstanceTest), 'InstanceTest undefined'
|
|
103
|
+
assert_includes InstanceTest.new.methods, :instance_test
|
|
104
|
+
FileUtils.touch File.expand_path(File.dirname(__FILE__) + '/fixtures/apps/helpers/instance_methods_helpers.rb')
|
|
105
|
+
Tennpipes.reload!
|
|
106
|
+
assert defined?(InstanceTest), 'InstanceTest undefined'
|
|
107
|
+
assert_includes InstanceTest.new.methods, :instance_test
|
|
108
|
+
ensure
|
|
109
|
+
FileUtils.rm tmp_file
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
2
|
+
|
|
3
|
+
describe "Routing" do
|
|
4
|
+
it 'should perform restul routing' do
|
|
5
|
+
mock_app do
|
|
6
|
+
controller :parent => :parents do
|
|
7
|
+
get :index, :with => :asset_id do
|
|
8
|
+
"#{url_for(:index, params[:parent_id], :asset_id => params[:asset_id])} get"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
put :index, :with => :asset_id do
|
|
12
|
+
"#{url_for(:index, params[:parent_id], :asset_id => params[:asset_id])} put"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
post :index, :with => :asset_id do
|
|
16
|
+
"#{url_for(:index, :parent_id => params[:parent_id], :asset_id => params[:asset_id])} post"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
delete :index, :with => :asset_id do
|
|
20
|
+
"#{url_for(:index, params[:parent_id], :asset_id => params[:asset_id])} delete"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
get "/parents/1/hi"
|
|
25
|
+
assert_equal "/parents/1/hi get", body
|
|
26
|
+
put "/parents/1/hi"
|
|
27
|
+
assert_equal "/parents/1/hi put", body
|
|
28
|
+
post "/parents/1/hi"
|
|
29
|
+
assert_equal "/parents/1/hi post", body
|
|
30
|
+
delete "/parents/1/hi"
|
|
31
|
+
assert_equal "/parents/1/hi delete", body
|
|
32
|
+
end
|
|
33
|
+
end
|
data/test/test_router.rb
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/fixtures/apps/simple')
|
|
3
|
+
|
|
4
|
+
describe "Router" do
|
|
5
|
+
|
|
6
|
+
def setup
|
|
7
|
+
Tennpipes.clear!
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'should dispatch paths correctly' do
|
|
11
|
+
app = lambda { |env|
|
|
12
|
+
[200, {
|
|
13
|
+
'X-ScriptName' => env['SCRIPT_NAME'],
|
|
14
|
+
'X-PathInfo' => env['PATH_INFO'],
|
|
15
|
+
'Content-Type' => 'text/plain'
|
|
16
|
+
}, [""]]
|
|
17
|
+
}
|
|
18
|
+
map = Tennpipes::Router.new(
|
|
19
|
+
{ :path => '/bar', :to => app },
|
|
20
|
+
{ :path => '/foo/bar', :to => app },
|
|
21
|
+
{ :path => '/foo', :to => app }
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
res = Rack::MockRequest.new(map).get("/")
|
|
25
|
+
assert res.not_found?
|
|
26
|
+
|
|
27
|
+
res = Rack::MockRequest.new(map).get("/qux")
|
|
28
|
+
assert res.not_found?
|
|
29
|
+
|
|
30
|
+
res = Rack::MockRequest.new(map).get("/foo")
|
|
31
|
+
assert res.ok?
|
|
32
|
+
assert_equal "/foo", res["X-ScriptName"]
|
|
33
|
+
assert_equal "/", res["X-PathInfo"]
|
|
34
|
+
|
|
35
|
+
res = Rack::MockRequest.new(map).get("/foo/")
|
|
36
|
+
assert res.ok?
|
|
37
|
+
assert_equal "/foo", res["X-ScriptName"]
|
|
38
|
+
assert_equal "/", res["X-PathInfo"]
|
|
39
|
+
|
|
40
|
+
res = Rack::MockRequest.new(map).get("/foo/bar")
|
|
41
|
+
assert res.ok?
|
|
42
|
+
assert_equal "/foo/bar", res["X-ScriptName"]
|
|
43
|
+
assert_equal "/", res["X-PathInfo"]
|
|
44
|
+
|
|
45
|
+
res = Rack::MockRequest.new(map).get("/foo/bar/")
|
|
46
|
+
assert res.ok?
|
|
47
|
+
assert_equal "/foo/bar", res["X-ScriptName"]
|
|
48
|
+
assert_equal "/", res["X-PathInfo"]
|
|
49
|
+
|
|
50
|
+
res = Rack::MockRequest.new(map).get("/foo///bar//quux")
|
|
51
|
+
assert_equal 200, res.status
|
|
52
|
+
assert res.ok?
|
|
53
|
+
assert_equal "/foo/bar", res["X-ScriptName"]
|
|
54
|
+
assert_equal "//quux", res["X-PathInfo"]
|
|
55
|
+
|
|
56
|
+
res = Rack::MockRequest.new(map).get("/foo/quux", "SCRIPT_NAME" => "/bleh")
|
|
57
|
+
assert res.ok?
|
|
58
|
+
assert_equal "/bleh/foo", res["X-ScriptName"]
|
|
59
|
+
assert_equal "/quux", res["X-PathInfo"]
|
|
60
|
+
|
|
61
|
+
res = Rack::MockRequest.new(map).get("/bar", 'HTTP_HOST' => 'foo.org')
|
|
62
|
+
assert res.ok?
|
|
63
|
+
assert_equal "/bar", res["X-ScriptName"]
|
|
64
|
+
assert_equal "/", res["X-PathInfo"]
|
|
65
|
+
|
|
66
|
+
res = Rack::MockRequest.new(map).get("/bar/", 'HTTP_HOST' => 'foo.org')
|
|
67
|
+
assert res.ok?
|
|
68
|
+
assert_equal "/bar", res["X-ScriptName"]
|
|
69
|
+
assert_equal "/", res["X-PathInfo"]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'should dispatch requests to cascade mounted apps' do
|
|
73
|
+
app = lambda { |env|
|
|
74
|
+
scary = !!env['PATH_INFO'].match(/scary/)
|
|
75
|
+
[scary ? 404 : 200, {
|
|
76
|
+
'X-ScriptName' => env['SCRIPT_NAME'],
|
|
77
|
+
'X-PathInfo' => env['PATH_INFO'],
|
|
78
|
+
'Content-Type' => 'text/plain'
|
|
79
|
+
}, [""]]
|
|
80
|
+
}
|
|
81
|
+
api = lambda { |env|
|
|
82
|
+
spooky = !!env['QUERY_STRING'].match(/spooky/)
|
|
83
|
+
[spooky ? 200 : 404, {
|
|
84
|
+
'X-API' => spooky,
|
|
85
|
+
'X-ScriptName' => env['SCRIPT_NAME'],
|
|
86
|
+
'X-PathInfo' => env['PATH_INFO'],
|
|
87
|
+
'Content-Type' => 'application/json'
|
|
88
|
+
}, [""]]
|
|
89
|
+
}
|
|
90
|
+
map = Tennpipes::Router.new(
|
|
91
|
+
{ :path => '/bar', :to => api },
|
|
92
|
+
{ :path => '/bar', :to => app }
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
res = Rack::MockRequest.new(map).get("/werewolf")
|
|
96
|
+
assert_equal 404, res.status
|
|
97
|
+
assert_equal nil, res["X-API"]
|
|
98
|
+
assert_equal nil, res["X-ScriptName"]
|
|
99
|
+
assert_equal nil, res["X-PathInfo"]
|
|
100
|
+
|
|
101
|
+
res = Rack::MockRequest.new(map).get("/bar/mitzvah")
|
|
102
|
+
assert res.ok?
|
|
103
|
+
assert_equal nil, res["X-API"]
|
|
104
|
+
assert_equal 'text/plain', res["Content-Type"]
|
|
105
|
+
assert_equal "/bar", res["X-ScriptName"]
|
|
106
|
+
assert_equal "/mitzvah", res["X-PathInfo"]
|
|
107
|
+
|
|
108
|
+
res = Rack::MockRequest.new(map).get("/bar?spooky")
|
|
109
|
+
assert res.ok?
|
|
110
|
+
assert_equal true, res["X-API"]
|
|
111
|
+
assert_equal 'application/json', res["Content-Type"]
|
|
112
|
+
assert_equal "/bar", res["X-ScriptName"]
|
|
113
|
+
assert_equal "/", res["X-PathInfo"]
|
|
114
|
+
|
|
115
|
+
res = Rack::MockRequest.new(map).get("/bar/scary")
|
|
116
|
+
assert_equal 404, res.status
|
|
117
|
+
assert_equal nil, res["X-API"]
|
|
118
|
+
assert_equal 'text/plain', res["Content-Type"]
|
|
119
|
+
assert_equal "/bar", res["X-ScriptName"]
|
|
120
|
+
assert_equal "/scary", res["X-PathInfo"]
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it 'should dispatch requests to cascade mounted apps and not cascade ok statuses' do
|
|
124
|
+
|
|
125
|
+
api = mock_app do
|
|
126
|
+
get 'scary' do
|
|
127
|
+
"1"
|
|
128
|
+
end
|
|
129
|
+
set :cascade, true
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
app = mock_app do
|
|
133
|
+
get 'scary' do
|
|
134
|
+
"2"
|
|
135
|
+
end
|
|
136
|
+
set :cascade, false
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
app2 = mock_app do
|
|
140
|
+
get 'terrifying' do
|
|
141
|
+
""
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
map = Tennpipes::Router.new(
|
|
146
|
+
{ :path => '/bar', :to => api },
|
|
147
|
+
{ :path => '/bar', :to => app },
|
|
148
|
+
{ :path => '/bar', :to => app2 }
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
res = Rack::MockRequest.new(map).get("/bar/scary")
|
|
152
|
+
assert res.ok?
|
|
153
|
+
#asserting that on ok we're good to go
|
|
154
|
+
assert_equal "1", res.body
|
|
155
|
+
|
|
156
|
+
res = Rack::MockRequest.new(map).get("/bar/terrifying")
|
|
157
|
+
assert !res.ok?
|
|
158
|
+
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
it 'should dispatch requests to cascade mounted apps until it sees a cascade == false or []g' do
|
|
162
|
+
app = mock_app do
|
|
163
|
+
get 'scary' do
|
|
164
|
+
""
|
|
165
|
+
end
|
|
166
|
+
set :cascade, []
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
app2 = mock_app do
|
|
170
|
+
get 'terrifying' do
|
|
171
|
+
""
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
map = Tennpipes::Router.new(
|
|
176
|
+
{ :path => '/bar', :to => app },
|
|
177
|
+
{ :path => '/bar', :to => app2 }
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
request_case = lambda {
|
|
181
|
+
Rack::MockRequest.new(map).get("/bar/terrifying")
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
app.cascade = false
|
|
185
|
+
assert !request_case.call.ok?
|
|
186
|
+
|
|
187
|
+
app.cascade = true
|
|
188
|
+
assert request_case.call.ok?
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
it 'should dispatches hosts correctly' do
|
|
192
|
+
map = Tennpipes::Router.new(
|
|
193
|
+
{ :host => "foo.org", :to => lambda { |env|
|
|
194
|
+
[200,
|
|
195
|
+
{ "Content-Type" => "text/plain",
|
|
196
|
+
"X-Position" => "foo.org",
|
|
197
|
+
"X-Host" => env["HTTP_HOST"] || env["SERVER_NAME"],
|
|
198
|
+
}, [""]]}},
|
|
199
|
+
{ :host => "subdomain.foo.org", :to => lambda { |env|
|
|
200
|
+
[200,
|
|
201
|
+
{ "Content-Type" => "text/plain",
|
|
202
|
+
"X-Position" => "subdomain.foo.org",
|
|
203
|
+
"X-Host" => env["HTTP_HOST"] || env["SERVER_NAME"],
|
|
204
|
+
}, [""]]}},
|
|
205
|
+
{ :host => /.*\.bar.org/, :to => lambda { |env|
|
|
206
|
+
[200,
|
|
207
|
+
{ "Content-Type" => "text/plain",
|
|
208
|
+
"X-Position" => "bar.org",
|
|
209
|
+
"X-Host" => env["HTTP_HOST"] || env["SERVER_NAME"],
|
|
210
|
+
}, [""]]}}
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "bar.org")
|
|
214
|
+
assert res.not_found?
|
|
215
|
+
|
|
216
|
+
res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "at.bar.org")
|
|
217
|
+
assert res.ok?
|
|
218
|
+
assert_equal "bar.org", res["X-Position"]
|
|
219
|
+
|
|
220
|
+
res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "foo.org")
|
|
221
|
+
assert res.ok?
|
|
222
|
+
assert_equal "foo.org", res["X-Position"]
|
|
223
|
+
|
|
224
|
+
res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "subdomain.foo.org", "SERVER_NAME" => "foo.org")
|
|
225
|
+
assert res.ok?
|
|
226
|
+
assert_equal "subdomain.foo.org", res["X-Position"]
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
it 'should works with tennpipes core applications' do
|
|
230
|
+
Tennpipes.mount("simple_demo").host("tennpipes.org")
|
|
231
|
+
assert_equal ["simple_demo"], Tennpipes.mounted_apps.map(&:name)
|
|
232
|
+
assert_equal ["tennpipes.org"], Tennpipes.mounted_apps.map(&:app_host)
|
|
233
|
+
|
|
234
|
+
res = Rack::MockRequest.new(Tennpipes.application).get("/")
|
|
235
|
+
assert res.not_found?
|
|
236
|
+
|
|
237
|
+
res = Rack::MockRequest.new(Tennpipes.application).get("/", "HTTP_HOST" => "bar.org")
|
|
238
|
+
assert res.not_found?
|
|
239
|
+
|
|
240
|
+
res = Rack::MockRequest.new(Tennpipes.application).get("/", "HTTP_HOST" => "tennpipes.org")
|
|
241
|
+
assert res.ok?
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
it 'should works with tennpipes applications' do
|
|
245
|
+
Tennpipes.mount("simple_demo").to("/foo").host(/.*\.tennpipes.org/)
|
|
246
|
+
|
|
247
|
+
res = Rack::MockRequest.new(Tennpipes.application).get("/")
|
|
248
|
+
assert res.not_found?
|
|
249
|
+
|
|
250
|
+
res = Rack::MockRequest.new(Tennpipes.application).get("/", "HTTP_HOST" => "bar.org")
|
|
251
|
+
assert res.not_found?
|
|
252
|
+
|
|
253
|
+
res = Rack::MockRequest.new(Tennpipes.application).get("/", "HTTP_HOST" => "tennpipes.org")
|
|
254
|
+
assert res.not_found?
|
|
255
|
+
|
|
256
|
+
res = Rack::MockRequest.new(Tennpipes.application).get("/none", "HTTP_HOST" => "foo.tennpipes.org")
|
|
257
|
+
assert res.not_found?
|
|
258
|
+
|
|
259
|
+
res = Rack::MockRequest.new(Tennpipes.application).get("/foo", "HTTP_HOST" => "bar.tennpipes.org")
|
|
260
|
+
assert res.ok?
|
|
261
|
+
|
|
262
|
+
res = Rack::MockRequest.new(Tennpipes.application).get("/foo/", "HTTP_HOST" => "bar.tennpipes.org")
|
|
263
|
+
assert res.ok?
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
it 'should keep the same environment object' do
|
|
267
|
+
app = lambda { |env|
|
|
268
|
+
env['path'] = env['PATH_INFO']
|
|
269
|
+
[200, {'Content-Type' => 'text/plain'}, [""]]
|
|
270
|
+
}
|
|
271
|
+
map = Tennpipes::Router.new(
|
|
272
|
+
{ :path => '/bar', :to => app },
|
|
273
|
+
{ :path => '/foo/bar', :to => app },
|
|
274
|
+
{ :path => '/foo', :to => app }
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
env = Rack::MockRequest.env_for("/bar/foo")
|
|
278
|
+
map.call(env)
|
|
279
|
+
assert_equal "/foo", env["path"]
|
|
280
|
+
end
|
|
281
|
+
end
|