Skip to content

Commit 6ddf5d8

Browse files
committed
Add tests for streaming chunks + a few minor fixes.
1 parent bfc45da commit 6ddf5d8

File tree

5 files changed

+80
-19
lines changed

5 files changed

+80
-19
lines changed

actionpack/lib/action_controller/metal/live.rb

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,6 @@ def initialize(response)
171171
@ignore_disconnect = false
172172
end
173173

174-
# ActionDispatch::Response delegates #to_ary to the internal
175-
# ActionDispatch::Response::Buffer, defining #to_ary is an indicator that the
176-
# response body can be buffered and/or cached by Rack middlewares, this is not
177-
# the case for Live responses so we undefine it for this Buffer subclass.
178-
undef_method :to_ary
179-
180174
def write(string)
181175
unless @response.committed?
182176
@response.headers["Cache-Control"] ||= "no-cache"

actionpack/lib/action_dispatch/http/response.rb

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,18 @@ def initialize(response, buf)
105105
@str_body = nil
106106
end
107107

108+
BODY_METHODS = { to_ary: true }
109+
110+
def respond_to?(method, include_private = false)
111+
if BODY_METHODS.key?(method)
112+
@buf.respond_to?(method)
113+
else
114+
super
115+
end
116+
end
117+
108118
def to_ary
109-
@buf.respond_to?(:to_ary) ?
110-
@buf.to_ary :
111-
@buf.each
119+
@buf.to_ary
112120
end
113121

114122
def body
@@ -499,6 +507,8 @@ def initialize(response)
499507
@response = response
500508
end
501509

510+
attr :response
511+
502512
def close
503513
# Rack "close" maps to Response#abort, and **not** Response#close (which is used
504514
# when the controller's finished writing)

actionpack/test/controller/new_base/render_streaming_test.rb

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,44 +45,78 @@ def explicit_cache
4545

4646
class StreamingTest < Rack::TestCase
4747
test "rendering with streaming enabled at the class level" do
48+
env = Rack::MockRequest.env_for("/render_streaming/basic/hello_world")
49+
status, headers, body = app.call(env)
50+
assert_streaming!(status, headers, body)
51+
assert_chunks ["Hello world", ", I'm here!"], body
52+
4853
get "/render_streaming/basic/hello_world"
4954
assert_body "Hello world, I'm here!"
50-
assert_streaming!
5155
end
5256

5357
test "rendering with streaming given to render" do
58+
env = Rack::MockRequest.env_for("/render_streaming/basic/explicit")
59+
status, headers, body = app.call(env)
60+
assert_streaming!(status, headers, body)
61+
assert_chunks ["Hello world", ", I'm here!"], body
62+
5463
get "/render_streaming/basic/explicit"
5564
assert_body "Hello world, I'm here!"
56-
assert_streaming!
65+
assert_cache_control!
5766
end
5867

5968
test "rendering with streaming do not override explicit cache control given to render" do
69+
env = Rack::MockRequest.env_for("/render_streaming/basic/explicit_cache")
70+
status, headers, body = app.call(env)
71+
assert_streaming!(status, headers, body)
72+
assert_chunks ["Hello world", ", I'm here!"], body
73+
6074
get "/render_streaming/basic/explicit_cache"
6175
assert_body "Hello world, I'm here!"
62-
assert_streaming! "private"
76+
assert_cache_control! "private"
6377
end
6478

6579
test "rendering with streaming no layout" do
80+
env = Rack::MockRequest.env_for("/render_streaming/basic/no_layout")
81+
status, headers, body = app.call(env)
82+
assert_streaming!(status, headers, body)
83+
assert_chunks ["Hello world"], body
84+
6685
get "/render_streaming/basic/no_layout"
6786
assert_body "Hello world"
68-
assert_streaming!
87+
assert_cache_control!
6988
end
7089

7190
test "skip rendering with streaming at render level" do
91+
env = Rack::MockRequest.env_for("/render_streaming/basic/skip")
92+
status, _, body = app.call(env)
93+
assert_equal 200, status
94+
assert_chunks ["Hello world, I'm here!"], body
95+
7296
get "/render_streaming/basic/skip"
7397
assert_body "Hello world, I'm here!"
7498
end
7599

76100
test "rendering with layout exception" do
101+
env = Rack::MockRequest.env_for("/render_streaming/basic/layout_exception")
102+
status, headers, body = app.call(env)
103+
assert_streaming!(status, headers, body)
104+
assert_chunks ["<body class=\"", "\"><script>window.location = \"/500.html\"</script></html>"], body
105+
77106
get "/render_streaming/basic/layout_exception"
78107
assert_body "<body class=\"\"><script>window.location = \"/500.html\"</script></html>"
79-
assert_streaming!
108+
assert_cache_control!
80109
end
81110

82111
test "rendering with template exception" do
112+
env = Rack::MockRequest.env_for("/render_streaming/basic/template_exception")
113+
status, headers, body = app.call(env)
114+
assert_streaming!(status, headers, body)
115+
assert_chunks ["\"><script>window.location = \"/500.html\"</script></html>"], body
116+
83117
get "/render_streaming/basic/template_exception"
84118
assert_body "\"><script>window.location = \"/500.html\"</script></html>"
85-
assert_streaming!
119+
assert_cache_control!
86120
end
87121

88122
test "rendering with template exception logs the exception" do
@@ -98,9 +132,28 @@ class StreamingTest < Rack::TestCase
98132
end
99133
end
100134

101-
def assert_streaming!(cache = "no-cache")
102-
assert_status 200
103-
assert_equal cache, headers["cache-control"]
135+
def assert_streaming!(status, headers, body)
136+
assert_equal 200, status
137+
138+
# It should not have a content length
139+
assert_nil headers["content-length"]
140+
141+
# The body should not respond to `#to_ary`
142+
assert_not_respond_to body, :to_ary
143+
end
144+
145+
def assert_cache_control!(value = "no-cache", headers: self.headers)
146+
assert_equal value, headers["cache-control"]
147+
end
148+
149+
def assert_chunks(expected, body)
150+
index = 0
151+
body.each do |chunk|
152+
assert_equal expected[index], chunk
153+
index += 1
154+
end
155+
156+
assert_equal expected.size, index
104157
end
105158
end
106159
end

actionview/lib/action_view/renderer/streaming_template_renderer.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def log_error(exception)
4242
# object that responds to each. This object is initialized with a block
4343
# that knows how to render the template.
4444
def render_template(view, template, layout_name = nil, locals = {}) # :nodoc:
45-
return [super.body] unless layout_name && template.supports_streaming?
45+
return [super.body] unless template.supports_streaming?
4646

4747
locals ||= {}
4848
layout = find_layout(layout_name, locals.keys, [formats.first])

actionview/lib/action_view/template/raw_file.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ def identifier
2020
def render(*args)
2121
::File.read(@filename)
2222
end
23+
24+
def supports_streaming?
25+
false
26+
end
2327
end
2428
end
2529
end

0 commit comments

Comments
 (0)