Skip to content

Commit 58f5541

Browse files
Improve test coverage. (#28)
1 parent 1e1341a commit 58f5541

File tree

12 files changed

+414
-200
lines changed

12 files changed

+414
-200
lines changed

lib/protocol/rack/adapter/rack2.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,11 @@ def self.make_response(env, response)
165165
end
166166

167167
headers.transform_values! do |value|
168-
value.is_a?(Array) ? value.join("\n") : value
168+
if value.is_a?(Array)
169+
value.join("\n")
170+
else
171+
value
172+
end
169173
end
170174

171175
[response.status, headers, body]

lib/protocol/rack/adapter/rack3.rb

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,6 @@ def self.parse_file(...)
3333
::Rack::Builder.parse_file(...)
3434
end
3535

36-
# Whether this adapter supports streaming responses.
37-
# Rack 3 supports streaming responses by default.
38-
#
39-
# @returns [Boolean] Always true for the Rack 3 adapter.
40-
def self.streaming?
41-
true
42-
end
43-
4436
# Create a Rack 3 environment hash for the request.
4537
# Sets up all required Rack 3 environment variables and processes the request.
4638
# Unlike Rack 2, this adapter doesn't set Rack version or threading flags.

lib/protocol/rack/body/enumerable.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,10 @@ def close(error = nil)
8787
# @parameter chunk [String] A chunk of the response body.
8888
def each(&block)
8989
@body.each(&block)
90+
rescue => error
91+
raise
9092
ensure
91-
self.close($!)
93+
self.close(error)
9294
end
9395

9496
# Check if the body is a streaming response.
@@ -105,8 +107,10 @@ def stream?
105107
# @parameter stream [Object] The stream to write the body to.
106108
def call(stream)
107109
@body.call(stream)
110+
rescue => error
111+
raise
108112
ensure
109-
self.close($!)
113+
self.close(error)
110114
end
111115

112116
# Read the next chunk from the response body.

lib/protocol/rack/response.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55

66
require_relative "body"
77
require_relative "constants"
8-
# require 'time'
98

109
require "protocol/http/response"
1110
require "protocol/http/headers"
11+
require "protocol/http/body/head"
1212

1313
module Protocol
1414
module Rack

test/protocol/rack/adapter.rb

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,62 @@
1919
expect(subject.parse_file(rackup_path)).to be_a(Proc)
2020
end
2121

22+
with ".make_response" do
23+
let(:env) {Rack::MockRequest.env_for("/")}
24+
25+
it "can make a response" do
26+
response = Protocol::HTTP::Response[200, headers: {}, body: ["Hello World!"]]
27+
status, headers, body = subject.make_response(env, response)
28+
29+
expect(status).to be == 200
30+
expect(headers).to be == {}
31+
expect(body.join).to be == "Hello World!"
32+
end
33+
34+
it "can make a streaming response" do
35+
stream_proc = lambda do |stream|
36+
stream.write("Hello Streaming World")
37+
stream.close
38+
end
39+
40+
body = Protocol::Rack::Body::Streaming.new(stream_proc)
41+
42+
response = Protocol::HTTP::Response[200, headers: {}, body: body]
43+
status, headers, body = subject.make_response(env, response)
44+
45+
expect(status).to be == 200
46+
if headers.include?(Protocol::Rack::RACK_HIJACK)
47+
hijack_proc = headers[Protocol::Rack::RACK_HIJACK]
48+
expect(hijack_proc).to be(:respond_to?, :call)
49+
else
50+
expect(body).to be(:respond_to?, :call)
51+
end
52+
end
53+
54+
it "can wrap headers" do
55+
response = Protocol::HTTP::Response[200, headers: {"x-custom" => "123"}, body: ["Hello World!"]]
56+
status, headers, body = subject.make_response(env, response)
57+
58+
x_custom = headers["x-custom"]
59+
60+
expect(x_custom).to (be == "123").or(be == ["123"])
61+
end
62+
63+
it "can wrap multi-value headers" do
64+
response = Protocol::HTTP::Response[200, headers: [["x-custom", "a=b"], ["x-custom", "x=y"]], body: ["Hello World!"]]
65+
66+
status, headers, body = subject.make_response(env, response)
67+
68+
x_custom = headers["x-custom"]
69+
70+
if subject::VERSION < "3"
71+
expect(x_custom).to be == "a=b\nx=y"
72+
else
73+
expect(x_custom).to be == ["a=b", "x=y"]
74+
end
75+
end
76+
end
77+
2278
AnApplication = Sus::Shared("an application") do
2379
include Protocol::Rack::ServerContext
2480

test/protocol/rack/adapter/rack2.rb

Lines changed: 112 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -3,121 +3,146 @@
33
# Released under the MIT License.
44
# Copyright, 2022-2025, by Samuel Williams.
55

6-
require "sus/fixtures/console"
76
require "protocol/rack/adapter/rack2"
87

8+
require "sus/fixtures/console"
9+
10+
require "rack"
11+
require "protocol/rack/body/streaming"
12+
913
describe Protocol::Rack::Adapter::Rack2 do
1014
include Sus::Fixtures::Console::CapturedLogger
1115

12-
let(:app) {->(env) {[200, {}, []]}}
13-
let(:adapter) {subject.new(app)}
14-
15-
let(:body) {Protocol::HTTP::Body::Buffered.new}
16-
let(:request) {Protocol::HTTP::Request.new("https", "example.com", "GET", "/", "http/1.1", Protocol::HTTP::Headers[{"accept" => "text/html"}], body)}
17-
let(:response) {adapter.call(request)}
18-
19-
with "set-cookie headers that has multiple values" do
20-
let(:app) {->(env) {[200, {"set-cookie" => "a=b\nx=y"}, []]}}
16+
with "#call" do
17+
let(:app) {->(env) {[200, {}, []]}}
18+
let(:adapter) {subject.new(app)}
2119

22-
it "can make a response newline separated headers" do
23-
expect(response.headers["set-cookie"]).to be == ["a=b", "x=y"]
24-
end
25-
end
26-
27-
with "content-length header" do
28-
let(:app) {->(env) {[200, {"content-length" => "10"}, ["1234567890"]]}}
20+
let(:body) {Protocol::HTTP::Body::Buffered.new}
21+
let(:request) {Protocol::HTTP::Request.new("https", "example.com", "GET", "/", "http/1.1", Protocol::HTTP::Headers[{"accept" => "text/html"}], body)}
22+
let(:response) {adapter.call(request)}
2923

30-
it "removes content-length header" do
31-
expect(response.headers).not.to be(:include?, "content-length")
24+
with "set-cookie headers that has multiple values" do
25+
let(:app) {->(env) {[200, {"set-cookie" => "a=b\nx=y"}, []]}}
26+
27+
it "can make a response newline separated headers" do
28+
expect(response.headers["set-cookie"]).to be == ["a=b", "x=y"]
29+
end
3230
end
33-
end
34-
35-
with "connection: close header" do
36-
let(:app) {->(env) {[200, {"connection" => "close"}, []]}}
3731

38-
it "removes content-length header" do
39-
expect(response.headers).not.to be(:include?, "connection")
40-
end
41-
end
42-
43-
with "body that responds to #to_path" do
44-
let(:body) {Array.new}
45-
let(:app) {->(env) {[200, {}, body]}}
46-
47-
it "should generate file body" do
48-
expect(body).to receive(:to_path).and_return("/dev/null")
49-
50-
expect(response.body).to be_a(Protocol::HTTP::Body::File)
51-
end
52-
53-
with "206 partial response status" do
54-
let(:app) {->(env) {[200, {}, body]}}
32+
with "content-length header" do
33+
let(:app) {->(env) {[200, {"content-length" => "10"}, ["1234567890"]]}}
5534

56-
it "should not modify partial responses" do
57-
expect(response.body).to be_a(Protocol::Rack::Body::Enumerable)
35+
it "removes content-length header" do
36+
expect(response.headers).not.to be(:include?, "content-length")
5837
end
5938
end
60-
end
61-
62-
with "a hijacked response" do
63-
let(:callback) {->(stream){}}
64-
let(:app) {->(env){[200, {"rack.hijack" => callback}, []]}}
6539

66-
it "should support hijacking" do
67-
expect(response.body).to be_a(Protocol::Rack::Body::Streaming)
68-
end
69-
end
70-
71-
with "response handling" do
72-
with "array response" do
73-
let(:app) {->(env) {[200, {}, ["Hello"]]}}
40+
with "connection: close header" do
41+
let(:app) {->(env) {[200, {"connection" => "close"}, []]}}
7442

75-
it "handles array response correctly" do
76-
expect(response.body).to be_a(Protocol::Rack::Body::Enumerable)
43+
it "removes content-length header" do
44+
expect(response.headers).not.to be(:include?, "connection")
7745
end
7846
end
7947

80-
# with "string response" do
81-
# let(:app) {->(env) {[200, {}, "Hello"]}}
82-
83-
# it "handles string response correctly" do
84-
# expect(response.status).to be == 500
85-
# expect(response.read).to be == "ArgumentError: Body must respond to #each!"
86-
# end
87-
# end
88-
end
89-
90-
with "header transformation" do
91-
with "array values" do
92-
let(:app) {->(env) {[200, {"x-custom" => "a\nb"}, []]}}
93-
94-
it "joins array values with newlines in response" do
95-
expect(response.headers["x-custom"]).to be == ["a", "b"]
48+
with "body that responds to #to_path" do
49+
let(:body) {Array.new}
50+
let(:app) {->(env) {[200, {}, body]}}
51+
52+
it "should generate file body" do
53+
expect(body).to receive(:to_path).and_return("/dev/null")
54+
55+
expect(response.body).to be_a(Protocol::HTTP::Body::File)
56+
end
57+
58+
with "206 partial response status" do
59+
let(:app) {->(env) {[200, {}, body]}}
60+
61+
it "should not modify partial responses" do
62+
expect(response.body).to be_a(Protocol::Rack::Body::Enumerable)
63+
end
9664
end
9765
end
9866

99-
with "non-array values" do
100-
let(:app) {->(env) {[200, {"x-custom" => "value"}, []]}}
67+
with "a hijacked response" do
68+
let(:callback) {->(stream){}}
69+
let(:app) {->(env){[200, {"rack.hijack" => callback}, []]}}
10170

102-
it "preserves non-array values" do
103-
expect(response.headers["x-custom"]).to be == ["value"]
71+
it "should support hijacking" do
72+
expect(response.body).to be_a(Protocol::Rack::Body::Streaming)
10473
end
10574
end
10675

107-
with "multiple set-cookie headers" do
108-
let(:app) {->(env) {[200, {"set-cookie" => "a=b\nx=y"}, []]}}
109-
110-
it "joins set-cookie headers with newlines" do
111-
expect(response.headers["set-cookie"]).to be == ["a=b", "x=y"]
76+
with "response handling" do
77+
with "array response" do
78+
let(:app) {->(env) {[200, {}, ["Hello"]]}}
79+
80+
it "handles array response correctly" do
81+
expect(response.body).to be_a(Protocol::Rack::Body::Enumerable)
82+
end
11283
end
11384
end
11485

115-
with "rack specific headers" do
116-
let(:app) {->(env) {[200, {"rack.hijack" => ->(stream){}}, []]}}
86+
with "header transformation" do
87+
with "array values" do
88+
let(:app) {->(env) {[200, {"x-custom" => "a\nb"}, []]}}
89+
90+
it "joins array values with newlines in response" do
91+
expect(response.headers["x-custom"]).to be == ["a", "b"]
92+
end
93+
end
94+
95+
with "non-array values" do
96+
let(:app) {->(env) {[200, {"x-custom" => "value"}, []]}}
97+
98+
it "preserves non-array values" do
99+
expect(response.headers["x-custom"]).to be == ["value"]
100+
end
101+
end
117102

118-
it "preserves rack specific headers in meta" do
119-
expect(response.headers).not.to be(:include?, "rack.hijack")
103+
with "multiple set-cookie headers" do
104+
let(:app) {->(env) {[200, {"set-cookie" => "a=b\nx=y"}, []]}}
105+
106+
it "joins set-cookie headers with newlines" do
107+
expect(response.headers["set-cookie"]).to be == ["a=b", "x=y"]
108+
end
120109
end
110+
111+
with "rack specific headers" do
112+
let(:app) {->(env) {[200, {"rack.hijack" => ->(stream){}}, []]}}
113+
114+
it "preserves rack specific headers in meta" do
115+
expect(response.headers).not.to be(:include?, "rack.hijack")
116+
end
117+
end
118+
end
119+
end
120+
121+
with "#make_response" do
122+
let(:env) {::Rack::MockRequest.env_for("/")}
123+
124+
it "can wrap response" do
125+
response = Protocol::HTTP::Response[200, headers: {}, body: []]
126+
status, headers, body = subject.make_response(env, response)
127+
128+
expect(status).to be == 200
129+
expect(headers).to be == {}
130+
expect(body).to be_a(Protocol::HTTP::Body::Buffered)
131+
expect(body).to be(:empty?)
132+
end
133+
134+
135+
it "can wrap streaming response" do
136+
streaming_body = Protocol::Rack::Body::Streaming.new(->(stream){})
137+
response = Protocol::HTTP::Response[200, headers: {}, body: streaming_body]
138+
139+
env[Protocol::Rack::RACK_IS_HIJACK] = true
140+
141+
status, headers, body = subject.make_response(env, response)
142+
143+
expect(status).to be == 200
144+
expect(headers).to have_keys(Protocol::Rack::RACK_HIJACK)
145+
expect(body).to be == []
121146
end
122147
end
123-
end
148+
end

0 commit comments

Comments
 (0)