File: exceptions_test.rb

package info (click to toggle)
rails 2%3A7.2.2.2%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 43,348 kB
  • sloc: ruby: 349,797; javascript: 30,703; yacc: 46; sql: 43; sh: 29; makefile: 27
file content (290 lines) | stat: -rw-r--r-- 9,395 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# frozen_string_literal: true

require "isolation/abstract_unit"
require "rack/test"

module ApplicationTests
  class MiddlewareExceptionsTest < ActiveSupport::TestCase
    include ActiveSupport::Testing::Isolation
    include Rack::Test::Methods

    def setup
      build_app
    end

    def teardown
      teardown_app
    end

    test "show exceptions middleware filter backtrace before logging" do
      controller :foo, <<-RUBY
        class FooController < ActionController::Base
          def index
            raise 'oops'
          end
        end
      RUBY

      log = capture(:stdout) do
        get("/foo", {}, "HTTPS" => "on")
        assert_equal 500, last_response.status
      end

      assert_no_match(/action_dispatch/, log, log)
      assert_match(/oops/, log, log)
    end

    test "renders active record exceptions as 404" do
      controller :foo, <<-RUBY
        class FooController < ActionController::Base
          def index
            raise ActiveRecord::RecordNotFound
          end
        end
      RUBY

      get "/foo", {}, { "HTTPS" => "on" }
      assert_equal 404, last_response.status
    end

    test "renders unknown http methods as 405" do
      request("/", { "REQUEST_METHOD" => "NOT_AN_HTTP_METHOD", "HTTPS" => "on" })
      assert_equal 405, last_response.status
    end

    test "renders unknown http methods as 405 when routes are used as the custom exceptions app" do
      app_file "config/routes.rb", <<-RUBY
        Rails.application.routes.draw do
        end
      RUBY

      add_to_config "config.exceptions_app = self.routes"

      app.config.action_dispatch.show_exceptions = :all

      request "/", { "REQUEST_METHOD" => "NOT_AN_HTTP_METHOD", "HTTPS" => "on" }
      assert_equal 405, last_response.status
    end

    test "renders unknown http formats as 406 when routes are used as the custom exceptions app" do
      controller :foo, <<-RUBY
        class FooController < ActionController::Base
          def index
            render plain: "rendering index!"
          end

          def not_acceptable
            render json: { error: "some error message" }, status: :not_acceptable
          end
        end
      RUBY

      app_file "config/routes.rb", <<-RUBY
        Rails.application.routes.draw do
          get "/foo", to: "foo#index"
          post "/foo", to: "foo#index"
          match "/406", to: "foo#not_acceptable", via: :all
        end
      RUBY

      add_to_config "config.exceptions_app = self.routes"
      add_to_config "config.action_dispatch.show_exceptions = :all"
      add_to_config "config.consider_all_requests_local = false"

      get "/foo", {}, { "HTTP_ACCEPT" => "invalid", "HTTPS" => "on" }
      assert_equal 406, last_response.status
      assert_not_equal "rendering index!", last_response.body

      get "/foo", {}, { "CONTENT_TYPE" => "invalid", "HTTPS" => "on" }
      assert_equal 406, last_response.status
      assert_not_equal "rendering index!", last_response.body

      get "/foo", {}, { "HTTP_ACCEPT" => "invalid", "CONTENT_TYPE" => "invalid", "HTTPS" => "on" }
      assert_equal 406, last_response.status
      assert_not_equal "rendering index!", last_response.body

      post "/foo", {}, { "HTTP_ACCEPT" => "invalid", "CONTENT_TYPE" => "invalid", "HTTPS" => "on" }
      assert_equal 406, last_response.status
      assert_not_equal "rendering index!", last_response.body
    end

    test "uses custom exceptions app" do
      add_to_config <<-RUBY
        config.exceptions_app = lambda do |env|
          [404, { "Content-Type" => "text/plain" }, ["YOU FAILED"]]
        end
      RUBY

      app.config.action_dispatch.show_exceptions = :all

      get("/foo", {}, "HTTPS" => "on")
      assert_equal 404, last_response.status
      assert_equal "YOU FAILED", last_response.body
    end

    test "URL generation error when action_dispatch.show_exceptions is set raises an exception" do
      controller :foo, <<-RUBY
        class FooController < ActionController::Base
          def index
            raise ActionController::UrlGenerationError
          end
        end
      RUBY

      app.config.action_dispatch.show_exceptions = :all

      get("/foo", {}, "HTTPS" => "on")
      assert_equal 500, last_response.status
    end

    test "unspecified route when action_dispatch.show_exceptions is not set raises an exception" do
      app.config.action_dispatch.show_exceptions = :none

      assert_raise(ActionController::RoutingError) do
        get("/foo", {}, "HTTPS" => "on")
      end
    end

    test "unspecified route when action_dispatch.show_exceptions is set shows 404" do
      app.config.action_dispatch.show_exceptions = :all

      assert_nothing_raised do
        get("/foo", {}, "HTTPS" => "on")
        assert_match "The page you were looking for doesn't exist.", last_response.body
      end
    end

    test "unspecified route when action_dispatch.show_exceptions and consider_all_requests_local are set shows diagnostics" do
      app.config.action_dispatch.show_exceptions = :all
      app.config.consider_all_requests_local = true

      assert_nothing_raised do
        get("/foo", {}, "HTTPS" => "on")
        assert_match "No route matches", last_response.body
      end
    end

    test "routing to a nonexistent controller when action_dispatch.show_exceptions and consider_all_requests_local are set shows diagnostics" do
      app_file "config/routes.rb", <<-RUBY
        Rails.application.routes.draw do
          resources :articles
        end
      RUBY

      app.config.action_dispatch.show_exceptions = :all
      app.config.consider_all_requests_local = true

      get("/articles", {}, "HTTPS" => "on")
      assert_match "<title>Action Controller: Exception caught</title>", last_response.body
    end

    test "displays diagnostics message when exception raised in template that contains UTF-8" do
      controller :foo, <<-RUBY
        class FooController < ActionController::Base
          def index
          end
        end
      RUBY

      app.config.action_dispatch.show_exceptions = :all
      app.config.consider_all_requests_local = true

      app_file "app/views/foo/index.html.erb", <<-ERB
        <% raise 'boooom' %>
        ✓測試テスト시험
      ERB

      get("/foo", { utf8: "✓" }, { "HTTPS" => "on" })
      assert_match(/boooom/, last_response.body)
      assert_match(/測試テスト시험/, last_response.body)
    end

    test "displays diagnostics message when malformed query parameters are provided" do
      controller :foo, <<-RUBY
        class FooController < ActionController::Base
          def index
          end
        end
      RUBY

      app.config.action_dispatch.show_exceptions = :all
      app.config.consider_all_requests_local = true

      get "/foo?x[y]=1&x[y][][w]=2", {}, "HTTPS" => "on"
      assert_equal 400, last_response.status
      assert_match "Invalid query parameters", last_response.body
    end

    test "displays diagnostics message when too deep query parameters are provided" do
      controller :foo, <<-RUBY
        class FooController < ActionController::Base
          def index
          end
        end
      RUBY

      app.config.action_dispatch.show_exceptions = :all
      app.config.consider_all_requests_local = true

      limit = Rack::Utils.param_depth_limit + 1
      malicious_url = "/foo?#{'[test]' * limit}=test"

      get(malicious_url, {}, "HTTPS" => "on")
      assert_equal 400, last_response.status
      assert_match "Invalid query parameters", last_response.body
    end

    test "displays statement invalid template correctly" do
      controller :foo, <<-RUBY
        class FooController < ActionController::Base
          def index
            raise ActiveRecord::StatementInvalid
          end
        end
      RUBY
      app.config.action_dispatch.show_exceptions = :all
      app.config.consider_all_requests_local = true
      app.config.action_dispatch.ignore_accept_header = false

      get("/foo", {}, "HTTPS" => "on")
      assert_equal 500, last_response.status
      assert_match "<title>Action Controller: Exception caught</title>", last_response.body
      assert_match "ActiveRecord::StatementInvalid", last_response.body

      get "/foo", {}, { "HTTP_ACCEPT" => "text/plain", "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest", "HTTPS" => "on" }
      assert_equal 500, last_response.status
      assert_equal "text/plain", last_response.media_type
      assert_match "ActiveRecord::StatementInvalid", last_response.body
    end

    test "show_exceptions :rescubale with a rescuable error" do
      controller :foo, <<-RUBY
        class FooController < ActionController::Base
          def index
            raise AbstractController::ActionNotFound
          end
        end
      RUBY

      app.config.action_dispatch.show_exceptions = :rescuable

      get "/foo", {}, { "HTTPS" => "on" }
      assert_equal 404, last_response.status
    end

    test "show_exceptions :rescubale with a non-rescuable error" do
      controller :foo, <<-RUBY
        class FooController < ActionController::Base
          def index
            raise 'oops'
          end
        end
      RUBY

      app.config.action_dispatch.show_exceptions = :rescuable

      error = assert_raises(RuntimeError) { get("/foo", {}, { "HTTPS" => "on" }) }
      assert_equal "oops", error.message
    end
  end
end