Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 198 lines (164 sloc) 5.696 kb
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
1 require 'uri'
2 require 'stringio'
98a61aa @josh Require 'rack' from mock.rb since it references Rack::VERSION
josh authored
3 require 'rack'
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
4 require 'rack/lint'
5 require 'rack/utils'
7f889ec @chneukirchen Introduce Rack::Response::Helpers and make MockResponse use them, too.
chneukirchen authored
6 require 'rack/response'
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
7
8 module Rack
376fa1e @chneukirchen Add RDocs
chneukirchen authored
9 # Rack::MockRequest helps testing your Rack application without
10 # actually using HTTP.
11 #
390988d @dlee Add #patch to MockRequest
dlee authored
12 # After performing a request on a URL with get/post/put/patch/delete, it
376fa1e @chneukirchen Add RDocs
chneukirchen authored
13 # returns a MockResponse with useful helper methods for effective
14 # testing.
15 #
16 # You can pass a hash with additional configuration to the
390988d @dlee Add #patch to MockRequest
dlee authored
17 # get/post/put/patch/delete.
376fa1e @chneukirchen Add RDocs
chneukirchen authored
18 # <tt>:input</tt>:: A String or IO-like to be used as rack.input.
19 # <tt>:fatal</tt>:: Raise a FatalWarning if the app writes to rack.errors.
20 # <tt>:lint</tt>:: If true, wrap the application in a Rack::Lint.
230d62c @chneukirchen Fix trailing whitespace. Sigh.
chneukirchen authored
21
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
22 class MockRequest
23 class FatalWarning < RuntimeError
24 end
25
26 class FatalWarner
27 def puts(warning)
28 raise FatalWarning, warning
29 end
30
31 def write(warning)
32 raise FatalWarning, warning
33 end
34
35 def flush
36 end
30a3550 @chneukirchen Add some more edge-case tests to improve coverage
chneukirchen authored
37
38 def string
39 ""
40 end
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
41 end
42
43 DEFAULT_ENV = {
fc6320a @raggi Update Rack::Mock to use Rack::VERSION too
raggi authored
44 "rack.version" => Rack::VERSION,
71030b9 @josh Revert "Add common HTTP strings to Rack::Const"
josh authored
45 "rack.input" => StringIO.new,
46 "rack.errors" => StringIO.new,
47 "rack.multithread" => true,
48 "rack.multiprocess" => true,
49 "rack.run_once" => false,
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
50 }
51
2cd911e @chneukirchen Add support for mocking all request methods
chneukirchen authored
52 def initialize(app)
53 @app = app
54 end
55
131d9fd @soulim Follow-up for the pull request #737
soulim authored
56 def get(uri, opts={}) request(GET, uri, opts) end
57 def post(uri, opts={}) request(POST, uri, opts) end
58 def put(uri, opts={}) request(PUT, uri, opts) end
59 def patch(uri, opts={}) request(PATCH, uri, opts) end
60 def delete(uri, opts={}) request(DELETE, uri, opts) end
61 def head(uri, opts={}) request(HEAD, uri, opts) end
62 def options(uri, opts={}) request(OPTIONS, uri, opts) end
63
64 def request(method=GET, uri="", opts={})
f428736 @chneukirchen MockRequest can now only create the Rack environment
chneukirchen authored
65 env = self.class.env_for(uri, opts.merge(:method => method))
66
67 if opts[:lint]
68 app = Rack::Lint.new(@app)
69 else
70 app = @app
71 end
72
71030b9 @josh Revert "Add common HTTP strings to Rack::Const"
josh authored
73 errors = env["rack.errors"]
4485088 @rkh Have MockRequest call close on the body rather than MockResponse.
rkh authored
74 status, headers, body = app.call(env)
75 MockResponse.new(status, headers, body, errors)
76 ensure
77 body.close if body.respond_to?(:close)
f428736 @chneukirchen MockRequest can now only create the Rack environment
chneukirchen authored
78 end
79
f467f1b @raggi Fix URI parsing on 1.8.7, also address perf
raggi authored
80 # For historical reasons, we're pinning to RFC 2396. It's easier for users
81 # and we get support from ruby 1.8 to 2.2 using this method.
82 def self.parse_uri_rfc2396(uri)
83 @parser ||= defined?(URI::RFC2396_Parser) ? URI::RFC2396_Parser.new : URI
84 @parser.parse(uri)
85 end
86
376fa1e @chneukirchen Add RDocs
chneukirchen authored
87 # Return the Rack environment used for a request to +uri+.
f428736 @chneukirchen MockRequest can now only create the Rack environment
chneukirchen authored
88 def self.env_for(uri="", opts={})
f467f1b @raggi Fix URI parsing on 1.8.7, also address perf
raggi authored
89 uri = parse_uri_rfc2396(uri)
c4d2433 @josh MockRequest should prepend slash to uri path
josh authored
90 uri.path = "/#{uri.path}" unless uri.path[0] == ?/
91
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
92 env = DEFAULT_ENV.dup
93
131d9fd @soulim Follow-up for the pull request #737
soulim authored
94 env[REQUEST_METHOD] = opts[:method] ? opts[:method].to_s.upcase : GET
95 env[SERVER_NAME] = uri.host || "example.org"
96 env[SERVER_PORT] = uri.port ? uri.port.to_s : "80"
dc53a8c @schneems Less allocated objects on each request
schneems authored
97 env[QUERY_STRING] = uri.query.to_s
98 env[PATH_INFO] = (!uri.path || uri.path.empty?) ? "/" : uri.path
71030b9 @josh Revert "Add common HTTP strings to Rack::Const"
josh authored
99 env["rack.url_scheme"] = uri.scheme || "http"
131d9fd @soulim Follow-up for the pull request #737
soulim authored
100 env[HTTPS] = env["rack.url_scheme"] == "https" ? "on" : "off"
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
101
dc53a8c @schneems Less allocated objects on each request
schneems authored
102 env[SCRIPT_NAME] = opts[:script_name] || ""
be1b390 @chneukirchen Add a default SCRIPT_NAME
chneukirchen authored
103
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
104 if opts[:fatal]
71030b9 @josh Revert "Add common HTTP strings to Rack::Const"
josh authored
105 env["rack.errors"] = FatalWarner.new
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
106 else
71030b9 @josh Revert "Add common HTTP strings to Rack::Const"
josh authored
107 env["rack.errors"] = StringIO.new
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
108 end
109
8847705 @josh MockRequest should accept hash params
josh authored
110 if params = opts[:params]
131d9fd @soulim Follow-up for the pull request #737
soulim authored
111 if env[REQUEST_METHOD] == GET
8847705 @josh MockRequest should accept hash params
josh authored
112 params = Utils.parse_nested_query(params) if params.is_a?(String)
dc53a8c @schneems Less allocated objects on each request
schneems authored
113 params.update(Utils.parse_nested_query(env[QUERY_STRING]))
114 env[QUERY_STRING] = Utils.build_nested_query(params)
8847705 @josh MockRequest should accept hash params
josh authored
115 elsif !opts.has_key?(:input)
71030b9 @josh Revert "Add common HTTP strings to Rack::Const"
josh authored
116 opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
8847705 @josh MockRequest should accept hash params
josh authored
117 if params.is_a?(Hash)
5a2eae5 @josh Utils::Multipart.build_multipart returns nil if no UploadedFiles are …
josh authored
118 if data = Utils::Multipart.build_multipart(params)
119 opts[:input] = data
71030b9 @josh Revert "Add common HTTP strings to Rack::Const"
josh authored
120 opts["CONTENT_LENGTH"] ||= data.length.to_s
121 opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Utils::Multipart::MULTIPART_BOUNDARY}"
8847705 @josh MockRequest should accept hash params
josh authored
122 else
123 opts[:input] = Utils.build_nested_query(params)
124 end
125 else
126 opts[:input] = params
127 end
128 end
129 end
130
8a7a142 @deepj Encoding class can be used freely everywhere
deepj authored
131 empty_str = ''.force_encoding(Encoding::ASCII_8BIT)
f23e833 @takahashim rack.input should be ASCII-8BIT even if it's StringIO (for test)
takahashim authored
132 opts[:input] ||= empty_str
2cd911e @chneukirchen Add support for mocking all request methods
chneukirchen authored
133 if String === opts[:input]
4e53cc7 @manveru Set correct external_encoding for handlers that don't use RewindableI…
manveru authored
134 rack_input = StringIO.new(opts[:input])
2cd911e @chneukirchen Add support for mocking all request methods
chneukirchen authored
135 else
4e53cc7 @manveru Set correct external_encoding for handlers that don't use RewindableI…
manveru authored
136 rack_input = opts[:input]
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
137 end
138
8a7a142 @deepj Encoding class can be used freely everywhere
deepj authored
139 rack_input.set_encoding(Encoding::BINARY)
71030b9 @josh Revert "Add common HTTP strings to Rack::Const"
josh authored
140 env['rack.input'] = rack_input
4e53cc7 @manveru Set correct external_encoding for handlers that don't use RewindableI…
manveru authored
141
71030b9 @josh Revert "Add common HTTP strings to Rack::Const"
josh authored
142 env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s
9e14a54 @remi set CONTENT_LENGTH header in Rack::MockRequest.env_for so :input POST…
remi authored
143
f428736 @chneukirchen MockRequest can now only create the Rack environment
chneukirchen authored
144 opts.each { |field, value|
145 env[field] = value if String === field
146 }
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
147
f428736 @chneukirchen MockRequest can now only create the Rack environment
chneukirchen authored
148 env
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
149 end
150 end
151
376fa1e @chneukirchen Add RDocs
chneukirchen authored
152 # Rack::MockResponse provides useful helpers for testing your apps.
153 # Usually, you don't create the MockResponse on your own, but use
154 # MockRequest.
155
4d95f60 @tenderlove moving MockResponse underneath Rack::Response
tenderlove authored
156 class MockResponse < Rack::Response
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
157 # Headers
812ac75 @tenderlove refactor Rack::MockResponse to be a subclass of Rack::Response, also …
tenderlove authored
158 attr_reader :original_headers
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
159
812ac75 @tenderlove refactor Rack::MockResponse to be a subclass of Rack::Response, also …
tenderlove authored
160 # Errors
161 attr_accessor :errors
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
162
812ac75 @tenderlove refactor Rack::MockResponse to be a subclass of Rack::Response, also …
tenderlove authored
163 def initialize(status, headers, body, errors=StringIO.new(""))
164 @original_headers = headers
165 @errors = errors.string if errors.respond_to?(:string)
166 @body_string = nil
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
167
812ac75 @tenderlove refactor Rack::MockResponse to be a subclass of Rack::Response, also …
tenderlove authored
168 super(body, status, headers)
169 end
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
170
171 def =~(other)
812ac75 @tenderlove refactor Rack::MockResponse to be a subclass of Rack::Response, also …
tenderlove authored
172 body =~ other
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
173 end
174
175 def match(other)
812ac75 @tenderlove refactor Rack::MockResponse to be a subclass of Rack::Response, also …
tenderlove authored
176 body.match other
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
177 end
178
812ac75 @tenderlove refactor Rack::MockResponse to be a subclass of Rack::Response, also …
tenderlove authored
179 def body
180 # FIXME: apparently users of MockResponse expect the return value of
181 # MockResponse#body to be a string. However, the real response object
182 # returns the body as a list.
183 #
184 # See spec_showstatus.rb:
185 #
186 # should "not replace existing messages" do
187 # ...
188 # res.body.should == "foo!"
189 # end
190 super.join
191 end
7f889ec @chneukirchen Introduce Rack::Response::Helpers and make MockResponse use them, too.
chneukirchen authored
192
4d95f60 @tenderlove moving MockResponse underneath Rack::Response
tenderlove authored
193 def empty?
2c5b076 @dkubb Add 205 Reset Content to the list of statuses without a message body
dkubb authored
194 [201, 204, 205, 304].include? status
4d95f60 @tenderlove moving MockResponse underneath Rack::Response
tenderlove authored
195 end
0fac859 @chneukirchen Add MockRequest/MockResponse for easier testing
chneukirchen authored
196 end
197 end
Something went wrong with that request. Please try again.