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.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.rdoc +294 -0
  4. data/Rakefile +1 -0
  5. data/bin/tennpipes +8 -0
  6. data/lib/tennpipes-base.rb +196 -0
  7. data/lib/tennpipes-base/application.rb +175 -0
  8. data/lib/tennpipes-base/application/application_setup.rb +202 -0
  9. data/lib/tennpipes-base/application/authenticity_token.rb +25 -0
  10. data/lib/tennpipes-base/application/flash.rb +229 -0
  11. data/lib/tennpipes-base/application/params_protection.rb +129 -0
  12. data/lib/tennpipes-base/application/routing.rb +1002 -0
  13. data/lib/tennpipes-base/application/show_exceptions.rb +50 -0
  14. data/lib/tennpipes-base/caller.rb +53 -0
  15. data/lib/tennpipes-base/cli/adapter.rb +33 -0
  16. data/lib/tennpipes-base/cli/base.rb +105 -0
  17. data/lib/tennpipes-base/cli/console.rb +20 -0
  18. data/lib/tennpipes-base/cli/launcher.rb +103 -0
  19. data/lib/tennpipes-base/cli/rake.rb +50 -0
  20. data/lib/tennpipes-base/cli/rake_tasks.rb +72 -0
  21. data/lib/tennpipes-base/command.rb +38 -0
  22. data/lib/tennpipes-base/ext/sinatra.rb +29 -0
  23. data/lib/tennpipes-base/filter.rb +52 -0
  24. data/lib/tennpipes-base/images/404.png +0 -0
  25. data/lib/tennpipes-base/images/500.png +0 -0
  26. data/lib/tennpipes-base/loader.rb +202 -0
  27. data/lib/tennpipes-base/logger.rb +492 -0
  28. data/lib/tennpipes-base/module.rb +58 -0
  29. data/lib/tennpipes-base/mounter.rb +308 -0
  30. data/lib/tennpipes-base/path_router.rb +119 -0
  31. data/lib/tennpipes-base/path_router/compiler.rb +110 -0
  32. data/lib/tennpipes-base/path_router/error_handler.rb +8 -0
  33. data/lib/tennpipes-base/path_router/matcher.rb +123 -0
  34. data/lib/tennpipes-base/path_router/route.rb +169 -0
  35. data/lib/tennpipes-base/reloader.rb +309 -0
  36. data/lib/tennpipes-base/reloader/rack.rb +26 -0
  37. data/lib/tennpipes-base/reloader/storage.rb +55 -0
  38. data/lib/tennpipes-base/router.rb +98 -0
  39. data/lib/tennpipes-base/server.rb +119 -0
  40. data/lib/tennpipes-base/tasks.rb +21 -0
  41. data/lib/tennpipes-base/version.rb +20 -0
  42. data/lib/tennpipes-base/version.rb~ +20 -0
  43. data/test/fixtures/app_gem/Gemfile +4 -0
  44. data/test/fixtures/app_gem/app/app.rb +3 -0
  45. data/test/fixtures/app_gem/app_gem.gemspec +17 -0
  46. data/test/fixtures/app_gem/lib/app_gem.rb +7 -0
  47. data/test/fixtures/app_gem/lib/app_gem/version.rb +3 -0
  48. data/test/fixtures/apps/complex.rb +32 -0
  49. data/test/fixtures/apps/demo_app.rb +7 -0
  50. data/test/fixtures/apps/demo_demo.rb +7 -0
  51. data/test/fixtures/apps/demo_project/api/app.rb +7 -0
  52. data/test/fixtures/apps/demo_project/api/lib/api_lib.rb +3 -0
  53. data/test/fixtures/apps/demo_project/app.rb +7 -0
  54. data/test/fixtures/apps/external_apps/fake_lib.rb +1 -0
  55. data/test/fixtures/apps/external_apps/fake_root.rb +2 -0
  56. data/test/fixtures/apps/helpers/class_methods_helpers.rb +4 -0
  57. data/test/fixtures/apps/helpers/instance_methods_helpers.rb +4 -0
  58. data/test/fixtures/apps/helpers/support.rb +1 -0
  59. data/test/fixtures/apps/helpers/system_helpers.rb +8 -0
  60. data/test/fixtures/apps/kiq.rb +3 -0
  61. data/test/fixtures/apps/lib/myklass.rb +2 -0
  62. data/test/fixtures/apps/lib/myklass/mysubklass.rb +4 -0
  63. data/test/fixtures/apps/models/child.rb +2 -0
  64. data/test/fixtures/apps/models/parent.rb +5 -0
  65. data/test/fixtures/apps/mountable_apps/rack_apps.rb +15 -0
  66. data/test/fixtures/apps/mountable_apps/static.html +1 -0
  67. data/test/fixtures/apps/precompiled_app.rb +19 -0
  68. data/test/fixtures/apps/simple.rb +32 -0
  69. data/test/fixtures/apps/static.rb +10 -0
  70. data/test/fixtures/apps/system.rb +13 -0
  71. data/test/fixtures/apps/system_class_methods_demo.rb +7 -0
  72. data/test/fixtures/apps/system_instance_methods_demo.rb +7 -0
  73. data/test/fixtures/dependencies/a.rb +9 -0
  74. data/test/fixtures/dependencies/b.rb +4 -0
  75. data/test/fixtures/dependencies/c.rb +1 -0
  76. data/test/fixtures/dependencies/circular/e.rb +13 -0
  77. data/test/fixtures/dependencies/circular/f.rb +2 -0
  78. data/test/fixtures/dependencies/circular/g.rb +2 -0
  79. data/test/fixtures/dependencies/d.rb +4 -0
  80. data/test/fixtures/reloadable_apps/external/app/app.rb +6 -0
  81. data/test/fixtures/reloadable_apps/external/app/controllers/base.rb +6 -0
  82. data/test/fixtures/reloadable_apps/main/app.rb +10 -0
  83. data/test/helper.rb +30 -0
  84. data/test/test_application.rb +185 -0
  85. data/test/test_core.rb +93 -0
  86. data/test/test_csrf_protection.rb +208 -0
  87. data/test/test_dependencies.rb +57 -0
  88. data/test/test_filters.rb +389 -0
  89. data/test/test_flash.rb +168 -0
  90. data/test/test_locale.rb +21 -0
  91. data/test/test_logger.rb +295 -0
  92. data/test/test_mounter.rb +302 -0
  93. data/test/test_params_protection.rb +195 -0
  94. data/test/test_reloader_complex.rb +74 -0
  95. data/test/test_reloader_external.rb +21 -0
  96. data/test/test_reloader_simple.rb +101 -0
  97. data/test/test_reloader_system.rb +113 -0
  98. data/test/test_restful_routing.rb +33 -0
  99. data/test/test_router.rb +281 -0
  100. data/test/test_routing.rb +2328 -0
  101. metadata +301 -0
@@ -0,0 +1,93 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/helper')
2
+
3
+ describe "Core" do
4
+ def setup
5
+ Tennpipes.clear!
6
+ end
7
+
8
+ describe 'for core functionality' do
9
+ it 'should check some global methods' do
10
+ assert_respond_to Tennpipes, :root
11
+ assert_respond_to Tennpipes, :env
12
+ assert_respond_to Tennpipes, :application
13
+ assert_respond_to Tennpipes, :set_encoding
14
+ assert_respond_to Tennpipes, :load!
15
+ assert_respond_to Tennpipes, :reload!
16
+ assert_respond_to Tennpipes, :version
17
+ assert_respond_to Tennpipes, :configure_apps
18
+ end
19
+
20
+ it 'should validate global helpers' do
21
+ assert_equal :test, Tennpipes.env
22
+ assert_match /\/test/, Tennpipes.root
23
+ refute_nil Tennpipes.version
24
+ end
25
+
26
+ it 'should set correct utf-8 encoding' do
27
+ Tennpipes.set_encoding
28
+ assert_equal Encoding.default_external, Encoding::UTF_8
29
+ assert_equal Encoding.default_internal, Encoding::UTF_8
30
+ end
31
+
32
+ it 'should raise application error if I instantiate a new tennpipes application without mounted apps' do
33
+ text = capture_io { Tennpipes.application }
34
+ assert_match /No apps are mounted/, text.to_s
35
+ end
36
+
37
+ it 'should check before/after tennpipes load hooks' do
38
+ Tennpipes.before_load { @_foo = 1 }
39
+ Tennpipes.after_load { @_foo += 1 }
40
+ Tennpipes.load!
41
+ assert_equal 1, Tennpipes.before_load.size
42
+ assert_equal 1, Tennpipes.after_load.size
43
+ assert_equal 2, @_foo
44
+ end
45
+
46
+ it 'should add middlewares in front if specified' do
47
+ test = Class.new {
48
+ def initialize(app)
49
+ @app = app
50
+ end
51
+
52
+ def call(env)
53
+ status, headers, body = @app.call(env)
54
+ headers["Middleware-Called"] = "yes"
55
+ return status, headers, body
56
+ end
57
+ }
58
+
59
+ class Foo < Tennpipes::Application; end
60
+
61
+ Tennpipes.use(test)
62
+ Tennpipes.mount(Foo).to("/")
63
+
64
+ res = Rack::MockRequest.new(Tennpipes.application).get("/")
65
+ assert_equal "yes", res["Middleware-Called"]
66
+ end
67
+
68
+ it 'should properly set default options' do
69
+ mock_app do
70
+ default :foo, :bar
71
+ default :zoo, :baz
72
+ set :foo, :bam
73
+ set :moo, :bam
74
+ default :moo, :ban
75
+ end
76
+ assert_equal @app.settings.foo, :bam
77
+ assert_equal @app.settings.zoo, :baz
78
+ assert_equal @app.settings.moo, :bam
79
+ end
80
+
81
+ it 'should return a friendly 500' do
82
+ mock_app do
83
+ enable :show_exceptions
84
+ get(:index){ raise StandardError }
85
+ end
86
+
87
+ get "/"
88
+ assert_equal 500, status
89
+ assert body.include?("StandardError")
90
+ assert body.include?("<code>show_exceptions</code> setting")
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,208 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/helper')
2
+
3
+ describe "Application" do
4
+ before { Tennpipes.clear! }
5
+
6
+ describe 'CSRF protection' do
7
+ describe "with CSRF protection on" do
8
+ before do
9
+ mock_app do
10
+ enable :sessions
11
+ enable :protect_from_csrf
12
+ post('/'){ 'HI' }
13
+ end
14
+ end
15
+
16
+ it 'should not allow requests without tokens' do
17
+ post "/"
18
+ assert_equal 403, status
19
+ end
20
+
21
+ it 'should allow requests with correct tokens' do
22
+ post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "a"}
23
+ assert_equal 200, status
24
+ end
25
+
26
+ it 'should not allow requests with incorrect tokens' do
27
+ post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "b"}
28
+ assert_equal 403, status
29
+ end
30
+
31
+ it 'should allow requests with correct X-CSRF-TOKEN' do
32
+ post "/", {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "a"
33
+ assert_equal 200, status
34
+ end
35
+
36
+ it 'should not allow requests with incorrect X-CSRF-TOKEN' do
37
+ post "/", {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "b"
38
+ assert_equal 403, status
39
+ end
40
+
41
+ end
42
+
43
+ describe "without CSRF protection on" do
44
+ before do
45
+ mock_app do
46
+ enable :sessions
47
+ disable :protect_from_csrf
48
+ post('/'){ 'HI' }
49
+ end
50
+ end
51
+
52
+ it 'should allows requests without tokens' do
53
+ post "/"
54
+ assert_equal 200, status
55
+ end
56
+
57
+ it 'should allow requests with correct tokens' do
58
+ post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "a"}
59
+ assert_equal 200, status
60
+ end
61
+
62
+ it 'should allow requests with incorrect tokens' do
63
+ post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "b"}
64
+ assert_equal 200, status
65
+ end
66
+
67
+ it 'should allow requests with correct X-CSRF-TOKEN' do
68
+ post "/", {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "a"
69
+ assert_equal 200, status
70
+ end
71
+
72
+ it 'should allow requests with incorrect X-CSRF-TOKEN' do
73
+ post "/", {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "b"
74
+ assert_equal 200, status
75
+ end
76
+ end
77
+
78
+ describe "with optional CSRF protection" do
79
+ before do
80
+ mock_app do
81
+ enable :sessions
82
+ enable :protect_from_csrf
83
+ enable :allow_disabled_csrf
84
+ post('/on') { 'HI' }
85
+ post('/off', :csrf_protection => false) { 'HI' }
86
+ end
87
+ end
88
+
89
+ it 'should allow access to routes with csrf_protection off' do
90
+ post "/off"
91
+ assert_equal 200, status
92
+ end
93
+
94
+ it 'should not allow access to routes with csrf_protection on' do
95
+ post "/on"
96
+ assert_equal 403, status
97
+ assert_equal 'Forbidden', body
98
+ end
99
+ end
100
+
101
+ describe "with :except option that is using Proc" do
102
+ before do
103
+ mock_app do
104
+ enable :sessions
105
+ set :protect_from_csrf, :except => proc{|env| ["/", "/foo"].any?{|path| path == env['PATH_INFO'] }}
106
+ post("/") { "Hello" }
107
+ post("/foo") { "Hello, foo" }
108
+ post("/bar") { "Hello, bar" }
109
+ end
110
+ end
111
+
112
+ it 'should allow ignoring CSRF protection on specific routes' do
113
+ post "/"
114
+ assert_equal 200, status
115
+ post "/foo"
116
+ assert_equal 200, status
117
+ post "/bar"
118
+ assert_equal 403, status
119
+ end
120
+ end
121
+
122
+ describe "with :except option that is using String and Regexp" do
123
+ before do
124
+ mock_app do
125
+ enable :sessions
126
+ set :protect_from_csrf, :except => ["/a", %r{^/a.c$}]
127
+ post("/a") { "a" }
128
+ post("/abc") { "abc" }
129
+ post("/foo") { "foo" }
130
+ end
131
+ end
132
+
133
+ it 'should allow ignoring CSRF protection on specific routes' do
134
+ post "/a"
135
+ assert_equal 200, status
136
+ post "/abc"
137
+ assert_equal 200, status
138
+ post "/foo"
139
+ assert_equal 403, status
140
+ end
141
+ end
142
+
143
+ describe "with custom protection options" do
144
+ before do
145
+ mock_app do
146
+ enable :sessions
147
+ set :protect_from_csrf, :authenticity_param => 'foobar', :message => 'sucker!'
148
+ post("/a") { "a" }
149
+ end
150
+ end
151
+
152
+ it 'should allow configuring protection options' do
153
+ post "/a", {"foobar" => "a"}, 'rack.session' => {:csrf => "a"}
154
+ assert_equal 200, status
155
+ end
156
+
157
+ it 'should allow configuring message' do
158
+ post "/a"
159
+ assert_equal 403, status
160
+ assert_equal 'sucker!', body
161
+ end
162
+ end
163
+
164
+ describe "with middleware" do
165
+ before do
166
+ class Middleware < Sinatra::Base
167
+ post("/middleware") { "Hello, middleware" }
168
+ post("/dummy") { "Hello, dummy" }
169
+ end
170
+ mock_app do
171
+ enable :sessions
172
+ set :protect_from_csrf, :except => proc{|env| ["/", "/middleware"].any?{|path| path == env['PATH_INFO'] }}
173
+ use Middleware
174
+ post("/") { "Hello" }
175
+ end
176
+ end
177
+
178
+ it 'should allow ignoring CSRF protection on specific routes of middleware' do
179
+ post "/"
180
+ assert_equal 200, status
181
+ post "/middleware"
182
+ assert_equal 200, status
183
+ post "/dummy"
184
+ assert_equal 403, status
185
+ end
186
+ end
187
+
188
+ describe "with standard report layout" do
189
+ before do
190
+ mock_app do
191
+ enable :sessions
192
+ set :protect_from_csrf, :message => 'sucker!'
193
+ enable :report_csrf_failure
194
+ post("/a") { "a" }
195
+ error 403 do
196
+ halt 406, 'please, do not hack'
197
+ end
198
+ end
199
+ end
200
+
201
+ it 'should allow configuring protection options' do
202
+ post "/a"
203
+ assert_equal 406, status
204
+ assert_equal 'please, do not hack', body
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,57 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/helper')
2
+
3
+ describe "Dependencies" do
4
+ describe 'when we require a dependency that have another dependency' do
5
+ before do
6
+ @log_level = Tennpipes::Logger::Config[:test]
7
+ @io = StringIO.new
8
+ Tennpipes::Logger::Config[:test] = { :log_level => :error, :stream => @io }
9
+ Tennpipes::Logger.setup!
10
+ end
11
+
12
+ after do
13
+ Tennpipes::Logger::Config[:test] = @log_level
14
+ Tennpipes::Logger.setup!
15
+ end
16
+
17
+ it 'should raise an error without reloading it twice' do
18
+ capture_io do
19
+ assert_raises(RuntimeError) do
20
+ Tennpipes.require_dependencies(
21
+ Tennpipes.root("fixtures/dependencies/a.rb"),
22
+ Tennpipes.root("fixtures/dependencies/b.rb"),
23
+ Tennpipes.root("fixtures/dependencies/c.rb"),
24
+ Tennpipes.root("fixtures/dependencies/d.rb")
25
+ )
26
+ end
27
+ end
28
+ assert_equal 1, D
29
+ assert_match /RuntimeError - SomeThing/, @io.string
30
+ end
31
+
32
+ it 'should resolve dependency problems' do
33
+ capture_io do
34
+ Tennpipes.require_dependencies(
35
+ Tennpipes.root("fixtures/dependencies/a.rb"),
36
+ Tennpipes.root("fixtures/dependencies/b.rb"),
37
+ Tennpipes.root("fixtures/dependencies/c.rb")
38
+ )
39
+ end
40
+ assert_equal ["B", "C"], A_result
41
+ assert_equal "C", B_result
42
+ assert_equal "", @io.string
43
+ end
44
+
45
+ it 'should remove partially loaded constants' do
46
+ capture_io do
47
+ Tennpipes.require_dependencies(
48
+ Tennpipes.root("fixtures/dependencies/circular/e.rb"),
49
+ Tennpipes.root("fixtures/dependencies/circular/f.rb"),
50
+ Tennpipes.root("fixtures/dependencies/circular/g.rb")
51
+ )
52
+ end
53
+ assert_equal ["name"], F.fields
54
+ assert_equal "", @io.string
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,389 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/helper')
2
+
3
+ describe "Filters" do
4
+ it 'should filters by accept header' do
5
+ mock_app do
6
+ get '/foo', :provides => [:xml, :js] do
7
+ request.env['HTTP_ACCEPT']
8
+ end
9
+ end
10
+
11
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
12
+ assert ok?
13
+ assert_equal 'application/xml', body
14
+ assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
15
+
16
+ get '/foo.xml'
17
+ assert ok?
18
+ assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
19
+
20
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript' }
21
+ assert ok?
22
+ assert_equal 'application/javascript', body
23
+ assert_equal 'application/javascript;charset=utf-8', response.headers['Content-Type']
24
+
25
+ get '/foo.js'
26
+ assert ok?
27
+ assert_equal 'application/javascript;charset=utf-8', response.headers['Content-Type']
28
+
29
+ get '/foo', {}, { "HTTP_ACCEPT" => 'text/html' }
30
+ assert_equal 406, status
31
+ end
32
+
33
+ it 'should allow passing & halting in before filters' do
34
+ mock_app do
35
+ controller do
36
+ before { env['QUERY_STRING'] == 'secret' or pass }
37
+ get :index do
38
+ "secret index"
39
+ end
40
+ end
41
+
42
+ controller do
43
+ before { env['QUERY_STRING'] == 'halt' and halt 401, 'go away!' }
44
+ get :index do
45
+ "index"
46
+ end
47
+ end
48
+ end
49
+
50
+ get "/?secret"
51
+ assert_equal "secret index", body
52
+
53
+ get "/?halt"
54
+ assert_equal "go away!", body
55
+ assert_equal 401, status
56
+
57
+ get "/"
58
+ assert_equal "index", body
59
+ end
60
+
61
+ it 'should scope filters in the given controller' do
62
+ mock_app do
63
+ before { @global = 'global' }
64
+ after { @global = nil }
65
+
66
+ controller :foo do
67
+ before { @foo = :foo }
68
+ after { @foo = nil }
69
+ get("/") { [@foo, @bar, @global].compact.join(" ") }
70
+ end
71
+
72
+ get("/") { [@foo, @bar, @global].compact.join(" ") }
73
+
74
+ controller :bar do
75
+ before { @bar = :bar }
76
+ after { @bar = nil }
77
+ get("/") { [@foo, @bar, @global].compact.join(" ") }
78
+ end
79
+ end
80
+
81
+ get "/bar"
82
+ assert_equal "bar global", body
83
+
84
+ get "/foo"
85
+ assert_equal "foo global", body
86
+
87
+ get "/"
88
+ assert_equal "global", body
89
+ end
90
+
91
+ it 'should be able to access params in a before filter' do
92
+ username_from_before_filter = nil
93
+
94
+ mock_app do
95
+ before do
96
+ username_from_before_filter = params[:username]
97
+ end
98
+
99
+ get :users, :with => :username do
100
+ end
101
+ end
102
+ get '/users/josh'
103
+ assert_equal 'josh', username_from_before_filter
104
+ end
105
+
106
+ it 'should be able to access params normally when a before filter is specified' do
107
+ mock_app do
108
+ before { }
109
+ get :index do
110
+ params.inspect
111
+ end
112
+ end
113
+ get '/?test=what'
114
+ assert_equal '{"test"=>"what"}', body
115
+ end
116
+
117
+ it 'should be able to filter based on a path' do
118
+ mock_app do
119
+ before('/') { @test = "#{@test}before"}
120
+ get :index do
121
+ @test
122
+ end
123
+ get :main do
124
+ @test
125
+ end
126
+ end
127
+ get '/'
128
+ assert_equal 'before', body
129
+ get '/main'
130
+ assert_equal '', body
131
+ end
132
+
133
+ it 'should be able to filter based on a symbol' do
134
+ mock_app do
135
+ before(:index) { @test = 'before'}
136
+ get :index do
137
+ @test
138
+ end
139
+ get :main do
140
+ @test
141
+ end
142
+ end
143
+ get '/'
144
+ assert_equal 'before', body
145
+ get '/main'
146
+ assert_equal '', body
147
+ end
148
+
149
+ it 'should be able to filter based on a symbol for a controller' do
150
+ mock_app do
151
+ controller :foo do
152
+ before(:test) { @test = 'foo'}
153
+ get :test do
154
+ @test.to_s + " response"
155
+ end
156
+ end
157
+ controller :bar do
158
+ before(:test) { @test = 'bar'}
159
+ get :test do
160
+ @test.to_s + " response"
161
+ end
162
+ end
163
+ end
164
+ get '/foo/test'
165
+ assert_equal 'foo response', body
166
+ get '/bar/test'
167
+ assert_equal 'bar response', body
168
+ end
169
+
170
+ it 'should be able to filter based on a symbol or path' do
171
+ mock_app do
172
+ before(:index, '/main') { @test = 'before'}
173
+ get :index do
174
+ @test
175
+ end
176
+ get :main do
177
+ @test
178
+ end
179
+ end
180
+ get '/'
181
+ assert_equal 'before', body
182
+ get '/main'
183
+ assert_equal 'before', body
184
+ end
185
+
186
+ it 'should be able to filter based on a symbol or regexp' do
187
+ mock_app do
188
+ before(:index, /main/) { @test = 'before'}
189
+ get :index do
190
+ @test
191
+ end
192
+ get :main do
193
+ @test
194
+ end
195
+ get :profile do
196
+ @test
197
+ end
198
+ end
199
+ get '/'
200
+ assert_equal 'before', body
201
+ get '/main'
202
+ assert_equal 'before', body
203
+ get '/profile'
204
+ assert_equal '', body
205
+ end
206
+
207
+ it 'should be able to filter excluding based on a symbol' do
208
+ mock_app do
209
+ before(:except => :index) { @test = 'before'}
210
+ get :index do
211
+ @test
212
+ end
213
+ get :main do
214
+ @test
215
+ end
216
+ end
217
+ get '/'
218
+ assert_equal '', body
219
+ get '/main'
220
+ assert_equal 'before', body
221
+ end
222
+
223
+ it 'should be able to filter excluding based on a symbol when specify the multiple routes and use nested controller' do
224
+ mock_app do
225
+ controller :test, :nested do
226
+ before(:except => [:test1, :test2]) { @long = 'long'}
227
+ before(:except => [:test1]) { @short = 'short'}
228
+ get :test1 do
229
+ "#{@long} #{@short} normal"
230
+ end
231
+ get :test2 do
232
+ "#{@long} #{@short} normal"
233
+ end
234
+ get :test3 do
235
+ "#{@long} #{@short} normal"
236
+ end
237
+ end
238
+ end
239
+ get '/test/nested/test1'
240
+ assert_equal ' normal', body
241
+ get '/test/nested/test2'
242
+ assert_equal ' short normal', body
243
+ get '/test/nested/test3'
244
+ assert_equal 'long short normal', body
245
+ end
246
+
247
+ it 'should be able to filter based on a request param' do
248
+ mock_app do
249
+ before(:agent => /IE/) { @test = 'before'}
250
+ get :index do
251
+ @test
252
+ end
253
+ end
254
+ get '/'
255
+ assert_equal '', body
256
+ get "/", {}, {'HTTP_USER_AGENT' => 'This is IE'}
257
+ assert_equal 'before', body
258
+ end
259
+
260
+ it 'should be able to filter based on a symbol or path in multiple controller' do
261
+ mock_app do
262
+ controllers :foo do
263
+ before(:index, '/foo/main') { @test = 'before' }
264
+ get :index do
265
+ @test
266
+ end
267
+ get :main do
268
+ @test
269
+ end
270
+ end
271
+ controllers :bar do
272
+ before(:index, '/bar/main') { @test = 'also before' }
273
+ get :index do
274
+ @test
275
+ end
276
+ get :main do
277
+ @test
278
+ end
279
+ end
280
+ end
281
+ get '/foo'
282
+ assert_equal 'before', body
283
+ get '/bar'
284
+ assert_equal 'also before', body
285
+ get '/foo/main'
286
+ assert_equal 'before', body
287
+ get '/bar/main'
288
+ assert_equal 'also before', body
289
+ end
290
+
291
+ it 'should call before filters even if there was no match' do
292
+ test = nil
293
+ mock_app do
294
+ before(:index, '/foo') { test = 'before' }
295
+ get :index do
296
+ ''
297
+ end
298
+ end
299
+ get '/foo'
300
+ assert_equal 'before', test
301
+ end
302
+
303
+ it 'should ensure the call of before_filter at the first time' do
304
+ once = ''
305
+ mock_app do
306
+ before do
307
+ once += 'before'
308
+ end
309
+ get :index do
310
+ raise Exception, 'Oops'
311
+ end
312
+ post :index do
313
+ raise Exception, 'Oops'
314
+ end
315
+ end
316
+
317
+ post '/'
318
+ assert_equal 'before', once
319
+ end
320
+
321
+ it 'should call before filters only once' do
322
+ once = ''
323
+ mock_app do
324
+ error 500 do
325
+ 'error 500'
326
+ end
327
+ before do
328
+ once += 'before'
329
+ end
330
+ get :index do
331
+ raise Exception, 'Oops'
332
+ end
333
+ end
334
+
335
+ get '/'
336
+ assert_equal 'before', once
337
+ end
338
+
339
+ it 'should catch exceptions in before filters' do
340
+ doodle = nil
341
+ mock_app do
342
+ after do
343
+ doodle = 'Been after'
344
+ end
345
+ before do
346
+ raise StandardError, "before"
347
+ end
348
+ get :index do
349
+ doodle = 'Been now'
350
+ end
351
+ error 500 do
352
+ "We broke #{env['sinatra.error'].message}"
353
+ end
354
+ end
355
+
356
+ get '/'
357
+ assert_equal 'We broke before', body
358
+ assert_equal nil, doodle
359
+ end
360
+
361
+ it 'should catch exceptions in after filters if no exceptions caught before' do
362
+ doodle = ''
363
+ mock_app do
364
+ after do
365
+ doodle += ' and after'
366
+ raise StandardError, "after"
367
+ end
368
+ get :foo do
369
+ doodle = 'Been now'
370
+ raise StandardError, "now"
371
+ end
372
+ get :index do
373
+ doodle = 'Been now'
374
+ end
375
+ error 500 do
376
+ "We broke #{env['sinatra.error'].message}"
377
+ end
378
+ end
379
+
380
+ get '/foo'
381
+ assert_equal 'We broke now', body
382
+ assert_equal 'Been now', doodle
383
+
384
+ doodle = ''
385
+ get '/'
386
+ assert_equal 'We broke after', body
387
+ assert_equal 'Been now and after', doodle
388
+ end
389
+ end