activeresource 2.3.9.pre → 2.3.9
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activeresource might be problematic. Click here for more details.
- data/CHANGELOG +1 -1
- data/lib/active_resource/http_mock.rb +100 -9
- data/test/http_mock_test.rb +155 -0
- metadata +8 -11
data/CHANGELOG
CHANGED
@@ -29,7 +29,8 @@ module ActiveResource
|
|
29
29
|
#
|
30
30
|
# In order for a mock to deliver its content, the incoming request must match by the <tt>http_method</tt>,
|
31
31
|
# +path+ and <tt>request_headers</tt>. If no match is found an InvalidRequestError exception
|
32
|
-
# will be raised
|
32
|
+
# will be raised showing you what request it could not find a response for and also what requests and response
|
33
|
+
# pairs have been recorded so you can create a new mock for that request.
|
33
34
|
#
|
34
35
|
# ==== Example
|
35
36
|
# def setup
|
@@ -97,10 +98,79 @@ module ActiveResource
|
|
97
98
|
@@responses ||= []
|
98
99
|
end
|
99
100
|
|
100
|
-
# Accepts a block which declares a set of requests and responses for the HttpMock to respond to
|
101
|
-
#
|
102
|
-
|
103
|
-
|
101
|
+
# Accepts a block which declares a set of requests and responses for the HttpMock to respond to in
|
102
|
+
# the following format:
|
103
|
+
#
|
104
|
+
# mock.http_method(path, request_headers = {}, body = nil, status = 200, response_headers = {})
|
105
|
+
#
|
106
|
+
# === Example
|
107
|
+
#
|
108
|
+
# @matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person")
|
109
|
+
# ActiveResource::HttpMock.respond_to do |mock|
|
110
|
+
# mock.post "/people.xml", {}, @matz, 201, "Location" => "/people/1.xml"
|
111
|
+
# mock.get "/people/1.xml", {}, @matz
|
112
|
+
# mock.put "/people/1.xml", {}, nil, 204
|
113
|
+
# mock.delete "/people/1.xml", {}, nil, 200
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# Alternatively, accepts a hash of <tt>{Request => Response}</tt> pairs allowing you to generate
|
117
|
+
# these the following format:
|
118
|
+
#
|
119
|
+
# ActiveResource::Request.new(method, path, body, request_headers)
|
120
|
+
# ActiveResource::Response.new(body, status, response_headers)
|
121
|
+
#
|
122
|
+
# === Example
|
123
|
+
#
|
124
|
+
# Request.new(:#{method}, path, nil, request_headers)
|
125
|
+
#
|
126
|
+
# @matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person")
|
127
|
+
#
|
128
|
+
# create_matz = ActiveResource::Request.new(:post, '/people.xml', @matz, {})
|
129
|
+
# created_response = ActiveResource::Response.new("", 201, {"Location" => "/people/1.xml"})
|
130
|
+
# get_matz = ActiveResource::Request.new(:get, '/people/1.xml', nil)
|
131
|
+
# ok_response = ActiveResource::Response.new("", 200, {})
|
132
|
+
#
|
133
|
+
# pairs = {create_matz => created_response, get_matz => ok_response}
|
134
|
+
#
|
135
|
+
# ActiveResource::HttpMock.respond_to(pairs)
|
136
|
+
#
|
137
|
+
# Note, by default, every time you call +respond_to+, any previous request and response pairs stored
|
138
|
+
# in HttpMock will be deleted giving you a clean slate to work on.
|
139
|
+
#
|
140
|
+
# If you want to override this behaviour, pass in +false+ as the last argument to +respond_to+
|
141
|
+
#
|
142
|
+
# === Example
|
143
|
+
#
|
144
|
+
# ActiveResource::HttpMock.respond_to do |mock|
|
145
|
+
# mock.send(:get, "/people/1", {}, "XML1")
|
146
|
+
# end
|
147
|
+
# ActiveResource::HttpMock.responses.length #=> 1
|
148
|
+
#
|
149
|
+
# ActiveResource::HttpMock.respond_to(false) do |mock|
|
150
|
+
# mock.send(:get, "/people/2", {}, "XML2")
|
151
|
+
# end
|
152
|
+
# ActiveResource::HttpMock.responses.length #=> 2
|
153
|
+
#
|
154
|
+
# This also works with passing in generated pairs of requests and responses, again, just pass in false
|
155
|
+
# as the last argument:
|
156
|
+
#
|
157
|
+
# === Example
|
158
|
+
#
|
159
|
+
# ActiveResource::HttpMock.respond_to do |mock|
|
160
|
+
# mock.send(:get, "/people/1", {}, "XML1")
|
161
|
+
# end
|
162
|
+
# ActiveResource::HttpMock.responses.length #=> 1
|
163
|
+
#
|
164
|
+
# get_matz = ActiveResource::Request.new(:get, '/people/1.xml', nil)
|
165
|
+
# ok_response = ActiveResource::Response.new("", 200, {})
|
166
|
+
#
|
167
|
+
# pairs = {get_matz => ok_response}
|
168
|
+
#
|
169
|
+
# ActiveResource::HttpMock.respond_to(pairs, false)
|
170
|
+
# ActiveResource::HttpMock.responses.length #=> 2
|
171
|
+
def respond_to(*args) #:yields: mock
|
172
|
+
pairs = args.first || {}
|
173
|
+
reset! if args.last.class != FalseClass
|
104
174
|
responses.concat pairs.to_a
|
105
175
|
if block_given?
|
106
176
|
yield Responder.new(responses)
|
@@ -123,13 +193,21 @@ module ActiveResource
|
|
123
193
|
# def post(path, body, headers)
|
124
194
|
# request = ActiveResource::Request.new(:post, path, body, headers)
|
125
195
|
# self.class.requests << request
|
126
|
-
# self.class.responses.assoc(request)
|
196
|
+
# if response = self.class.responses.assoc(request)
|
197
|
+
# response[1]
|
198
|
+
# else
|
199
|
+
# raise InvalidRequestError.new("Could not find a response recorded for #{request.to_s} - Responses recorded are: - #{inspect_responses}")
|
200
|
+
# end
|
127
201
|
# end
|
128
202
|
module_eval <<-EOE, __FILE__, __LINE__ + 1
|
129
203
|
def #{method}(path, #{'body, ' if has_body}headers)
|
130
204
|
request = ActiveResource::Request.new(:#{method}, path, #{has_body ? 'body, ' : 'nil, '}headers)
|
131
205
|
self.class.requests << request
|
132
|
-
self.class.responses.assoc(request)
|
206
|
+
if response = self.class.responses.assoc(request)
|
207
|
+
response[1]
|
208
|
+
else
|
209
|
+
raise InvalidRequestError.new("Could not find a response recorded for \#{request.to_s} - Responses recorded are: \#{inspect_responses}")
|
210
|
+
end
|
133
211
|
end
|
134
212
|
EOE
|
135
213
|
end
|
@@ -148,16 +226,29 @@ module ActiveResource
|
|
148
226
|
attr_accessor :path, :method, :body, :headers
|
149
227
|
|
150
228
|
def initialize(method, path, body = nil, headers = {})
|
151
|
-
@method, @path, @body, @headers = method, path, body, headers
|
229
|
+
@method, @path, @body, @headers = method, path, body, headers
|
152
230
|
end
|
153
231
|
|
154
232
|
def ==(req)
|
155
|
-
path == req.path && method == req.method &&
|
233
|
+
path == req.path && method == req.method && headers_match?(req)
|
156
234
|
end
|
157
235
|
|
158
236
|
def to_s
|
159
237
|
"<#{method.to_s.upcase}: #{path} [#{headers}] (#{body})>"
|
160
238
|
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
def headers_match?(req)
|
243
|
+
# Ignore format header on equality if it's not defined
|
244
|
+
format_header = ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[method]
|
245
|
+
if headers[format_header].present? || req.headers[format_header].blank?
|
246
|
+
headers == req.headers
|
247
|
+
else
|
248
|
+
headers.dup.merge(format_header => req.headers[format_header]) == req.headers
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
161
252
|
end
|
162
253
|
|
163
254
|
class Response
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
|
3
|
+
class HttpMockTest < ActiveSupport::TestCase
|
4
|
+
def setup
|
5
|
+
@http = ActiveResource::HttpMock.new("http://example.com")
|
6
|
+
end
|
7
|
+
|
8
|
+
FORMAT_HEADER = { :get => 'Accept',
|
9
|
+
:put => 'Content-Type',
|
10
|
+
:post => 'Content-Type',
|
11
|
+
:delete => 'Accept',
|
12
|
+
:head => 'Accept'
|
13
|
+
}
|
14
|
+
|
15
|
+
[:post, :put, :get, :delete, :head].each do |method|
|
16
|
+
test "responds to simple #{method} request" do
|
17
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
18
|
+
mock.send(method, "/people/1", {FORMAT_HEADER[method] => "application/xml"}, "Response")
|
19
|
+
end
|
20
|
+
|
21
|
+
assert_equal "Response", request(method, "/people/1", FORMAT_HEADER[method] => "application/xml").body
|
22
|
+
end
|
23
|
+
|
24
|
+
test "adds format header by default to #{method} request" do
|
25
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
26
|
+
mock.send(method, "/people/1", {}, "Response")
|
27
|
+
end
|
28
|
+
|
29
|
+
assert_equal "Response", request(method, "/people/1", FORMAT_HEADER[method] => "application/xml").body
|
30
|
+
end
|
31
|
+
|
32
|
+
test "respond only when headers match header by default to #{method} request" do
|
33
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
34
|
+
mock.send(method, "/people/1", {"X-Header" => "X"}, "Response")
|
35
|
+
end
|
36
|
+
|
37
|
+
assert_equal "Response", request(method, "/people/1", "X-Header" => "X").body
|
38
|
+
assert_raise(ActiveResource::InvalidRequestError) { request(method, "/people/1") }
|
39
|
+
end
|
40
|
+
|
41
|
+
test "does not overwrite format header to #{method} request" do
|
42
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
43
|
+
mock.send(method, "/people/1", {FORMAT_HEADER[method] => "application/json"}, "Response")
|
44
|
+
end
|
45
|
+
|
46
|
+
assert_equal "Response", request(method, "/people/1", FORMAT_HEADER[method] => "application/json").body
|
47
|
+
end
|
48
|
+
|
49
|
+
test "ignores format header when there is only one response to same url in a #{method} request" do
|
50
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
51
|
+
mock.send(method, "/people/1", {}, "Response")
|
52
|
+
end
|
53
|
+
|
54
|
+
assert_equal "Response", request(method, "/people/1", FORMAT_HEADER[method] => "application/json").body
|
55
|
+
assert_equal "Response", request(method, "/people/1", FORMAT_HEADER[method] => "application/xml").body
|
56
|
+
end
|
57
|
+
|
58
|
+
test "responds correctly when format header is given to #{method} request" do
|
59
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
60
|
+
mock.send(method, "/people/1", {FORMAT_HEADER[method] => "application/xml"}, "XML")
|
61
|
+
mock.send(method, "/people/1", {FORMAT_HEADER[method] => "application/json"}, "Json")
|
62
|
+
end
|
63
|
+
|
64
|
+
assert_equal "XML", request(method, "/people/1", FORMAT_HEADER[method] => "application/xml").body
|
65
|
+
assert_equal "Json", request(method, "/people/1", FORMAT_HEADER[method] => "application/json").body
|
66
|
+
end
|
67
|
+
|
68
|
+
test "raises InvalidRequestError if no response found for the #{method} request" do
|
69
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
70
|
+
mock.send(method, "/people/1", {FORMAT_HEADER[method] => "application/xml"}, "XML")
|
71
|
+
end
|
72
|
+
|
73
|
+
assert_raise(::ActiveResource::InvalidRequestError) do
|
74
|
+
request(method, "/people/1", FORMAT_HEADER[method] => "application/json")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
test "allows you to send in pairs directly to the respond_to method" do
|
81
|
+
matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person")
|
82
|
+
|
83
|
+
create_matz = ActiveResource::Request.new(:post, '/people.xml', matz, {})
|
84
|
+
created_response = ActiveResource::Response.new("", 201, {"Location" => "/people/1.xml"})
|
85
|
+
get_matz = ActiveResource::Request.new(:get, '/people/1.xml', nil)
|
86
|
+
ok_response = ActiveResource::Response.new(matz, 200, {})
|
87
|
+
|
88
|
+
pairs = {create_matz => created_response, get_matz => ok_response}
|
89
|
+
|
90
|
+
ActiveResource::HttpMock.respond_to(pairs)
|
91
|
+
assert_equal 2, ActiveResource::HttpMock.responses.length
|
92
|
+
assert_equal "", ActiveResource::HttpMock.responses.assoc(create_matz)[1].body
|
93
|
+
assert_equal matz, ActiveResource::HttpMock.responses.assoc(get_matz)[1].body
|
94
|
+
end
|
95
|
+
|
96
|
+
test "resets all mocked responses on each call to respond_to with a block by default" do
|
97
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
98
|
+
mock.send(:get, "/people/1", {}, "XML1")
|
99
|
+
end
|
100
|
+
assert_equal 1, ActiveResource::HttpMock.responses.length
|
101
|
+
|
102
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
103
|
+
mock.send(:get, "/people/2", {}, "XML2")
|
104
|
+
end
|
105
|
+
assert_equal 1, ActiveResource::HttpMock.responses.length
|
106
|
+
end
|
107
|
+
|
108
|
+
test "resets all mocked responses on each call to respond_to by passing pairs by default" do
|
109
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
110
|
+
mock.send(:get, "/people/1", {}, "XML1")
|
111
|
+
end
|
112
|
+
assert_equal 1, ActiveResource::HttpMock.responses.length
|
113
|
+
|
114
|
+
matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person")
|
115
|
+
get_matz = ActiveResource::Request.new(:get, '/people/1.xml', nil)
|
116
|
+
ok_response = ActiveResource::Response.new(matz, 200, {})
|
117
|
+
ActiveResource::HttpMock.respond_to({get_matz => ok_response})
|
118
|
+
|
119
|
+
assert_equal 1, ActiveResource::HttpMock.responses.length
|
120
|
+
end
|
121
|
+
|
122
|
+
test "allows you to add new responses to the existing responses by calling a block" do
|
123
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
124
|
+
mock.send(:get, "/people/1", {}, "XML1")
|
125
|
+
end
|
126
|
+
assert_equal 1, ActiveResource::HttpMock.responses.length
|
127
|
+
|
128
|
+
ActiveResource::HttpMock.respond_to(false) do |mock|
|
129
|
+
mock.send(:get, "/people/2", {}, "XML2")
|
130
|
+
end
|
131
|
+
assert_equal 2, ActiveResource::HttpMock.responses.length
|
132
|
+
end
|
133
|
+
|
134
|
+
test "allows you to add new responses to the existing responses by passing pairs" do
|
135
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
136
|
+
mock.send(:get, "/people/1", {}, "XML1")
|
137
|
+
end
|
138
|
+
assert_equal 1, ActiveResource::HttpMock.responses.length
|
139
|
+
|
140
|
+
matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person")
|
141
|
+
get_matz = ActiveResource::Request.new(:get, '/people/1.xml', nil)
|
142
|
+
ok_response = ActiveResource::Response.new(matz, 200, {})
|
143
|
+
ActiveResource::HttpMock.respond_to({get_matz => ok_response}, false)
|
144
|
+
|
145
|
+
assert_equal 2, ActiveResource::HttpMock.responses.length
|
146
|
+
end
|
147
|
+
|
148
|
+
def request(method, path, headers = {}, body = nil)
|
149
|
+
if [:put, :post].include? method
|
150
|
+
@http.send(method, path, body, headers)
|
151
|
+
else
|
152
|
+
@http.send(method, path, headers)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activeresource
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
4
|
+
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 2
|
7
7
|
- 3
|
8
8
|
- 9
|
9
|
-
|
10
|
-
version: 2.3.9.pre
|
9
|
+
version: 2.3.9
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- David Heinemeier Hansson
|
@@ -15,7 +14,7 @@ autorequire: active_resource
|
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
16
|
|
18
|
-
date: 2010-
|
17
|
+
date: 2010-09-04 00:00:00 -07:00
|
19
18
|
default_executable:
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
@@ -29,8 +28,7 @@ dependencies:
|
|
29
28
|
- 2
|
30
29
|
- 3
|
31
30
|
- 9
|
32
|
-
|
33
|
-
version: 2.3.9.pre
|
31
|
+
version: 2.3.9
|
34
32
|
type: :runtime
|
35
33
|
version_requirements: *id001
|
36
34
|
description: Wraps web resources in model classes that can be manipulated through XML over REST.
|
@@ -72,6 +70,7 @@ files:
|
|
72
70
|
- test/fixtures/proxy.rb
|
73
71
|
- test/fixtures/street_address.rb
|
74
72
|
- test/format_test.rb
|
73
|
+
- test/http_mock_test.rb
|
75
74
|
- test/setter_trap.rb
|
76
75
|
has_rdoc: true
|
77
76
|
homepage: http://www.rubyonrails.org
|
@@ -92,13 +91,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
92
91
|
version: "0"
|
93
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
93
|
requirements:
|
95
|
-
- - "
|
94
|
+
- - ">="
|
96
95
|
- !ruby/object:Gem::Version
|
97
96
|
segments:
|
98
|
-
-
|
99
|
-
|
100
|
-
- 1
|
101
|
-
version: 1.3.1
|
97
|
+
- 0
|
98
|
+
version: "0"
|
102
99
|
requirements: []
|
103
100
|
|
104
101
|
rubyforge_project: activeresource
|