webmock 0.8.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,19 @@
1
+ #compatibility with Ruby 1.9.2 preview1 to allow reading raw responses
2
+ class StringIO
3
+ alias_method :read_nonblock, :sysread
4
+ end
5
+
1
6
  module WebMock
7
+
2
8
  class Response
3
9
  attr_reader :options
4
10
 
5
11
  def initialize(options = {})
6
- self.options = options
12
+ if options.is_a?(IO) || options.is_a?(String)
13
+ self.options = read_raw_response(options)
14
+ else
15
+ self.options = options
16
+ end
7
17
  @options[:headers] = Util::Headers.normalize_headers(@options[:headers]) unless @options[:headers].is_a?(Proc)
8
18
  end
9
19
 
@@ -39,6 +49,8 @@ module WebMock
39
49
  def ==(other)
40
50
  options == other.options
41
51
  end
52
+
53
+ private
42
54
 
43
55
  def stringify_body!
44
56
  if @options[:body].is_a?(IO)
@@ -47,6 +59,25 @@ module WebMock
47
59
  io.close
48
60
  end
49
61
  end
62
+
63
+ def read_raw_response(raw_response)
64
+ if raw_response.is_a?(IO)
65
+ string = raw_response.read
66
+ raw_response.close
67
+ raw_response = string
68
+ end
69
+ socket = Net::BufferedIO.new(raw_response)
70
+ response = Net::HTTPResponse.read_new(socket)
71
+ transfer_encoding = response.delete('transfer-encoding') #chunks were already read by curl
72
+ response.reading_body(socket, true) {}
73
+
74
+ options = {}
75
+ options[:headers] = {}
76
+ response.each_header {|name, value| options[:headers][name] = value}
77
+ options[:headers]['transfer-encoding'] = transfer_encoding if transfer_encoding
78
+ options[:body] = response.read_body
79
+ options
80
+ end
50
81
 
51
82
  end
52
83
  end
@@ -0,0 +1,40 @@
1
+ module WebMock
2
+
3
+ class ResponsesSequence
4
+
5
+ attr_accessor :times_to_repeat
6
+
7
+ def initialize(responses)
8
+ @times_to_repeat = 1
9
+ @responses = responses
10
+ @current_position = 0
11
+ end
12
+
13
+ def end?
14
+ @times_to_repeat == 0
15
+ end
16
+
17
+ def next_response
18
+ if @times_to_repeat > 0
19
+ response = @responses[@current_position]
20
+ increase_position
21
+ response
22
+ else
23
+ @responses.last
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def increase_position
30
+ if @current_position == (@responses.length - 1)
31
+ @current_position = 0
32
+ @times_to_repeat -= 1
33
+ else
34
+ @current_position += 1
35
+ end
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -7,7 +7,7 @@ module WebMock
7
7
  def self.normalize_headers(headers)
8
8
  return nil unless headers
9
9
  array = headers.map { |name, value|
10
- [name.to_s.split(/_|-/).map { |segment| segment.capitalize }.join("-"), value.to_s]
10
+ [name.to_s.split(/_|-/).map { |segment| segment.capitalize }.join("-"), value.is_a?(Regexp) ? value : value.to_s]
11
11
  }
12
12
  Hash[*array.flatten]
13
13
  end
@@ -11,15 +11,15 @@ module WebMock
11
11
  RequestProfile.new(method, uri)
12
12
  end
13
13
 
14
- def assert_requested(method, uri, options = {})
14
+ def assert_requested(method, uri, options = {}, &block)
15
15
  expected_times_executed = options.delete(:times) || 1
16
- request = RequestProfile.new(method, uri, options)
16
+ request = RequestProfile.new(method, uri, options).with(&block)
17
17
  verifier = RequestExecutionVerifier.new(request, expected_times_executed)
18
18
  assertion_failure(verifier.failure_message) unless verifier.matches?
19
19
  end
20
20
 
21
- def assert_not_requested(method, uri, options = {})
22
- request = RequestProfile.new(method, uri, options)
21
+ def assert_not_requested(method, uri, options = {}, &block)
22
+ request = RequestProfile.new(method, uri, options).with(&block)
23
23
  verifier = RequestExecutionVerifier.new(request, options.delete(:times))
24
24
  assertion_failure(verifier.negative_failure_message) unless verifier.does_not_match?
25
25
  end
@@ -0,0 +1,20 @@
1
+ HTTP/1.1 200 OK
2
+ Content-Type: text/html; charset=UTF-8
3
+ Connection: Keep-Alive
4
+ Date: Sat, 23 Jan 2010 01:01:05 GMT
5
+ Content-Length: 438
6
+
7
+ <HTML>
8
+ <HEAD>
9
+ <TITLE>Example Web Page</TITLE>
10
+ </HEAD>
11
+ <body>
12
+ <p>You have reached this web page by typing &quot;example.com&quot;,
13
+ &quot;example.net&quot;,
14
+ or &quot;example.org&quot; into your web browser.</p>
15
+ <p>These domain names are reserved for use in documentation and are not available
16
+ for registration. See <a href="http://www.rfc-editor.org/rfc/rfc2606.txt">RFC
17
+ 2606</a>, Section 3.</p>
18
+ </BODY>
19
+ </HTML>
20
+
@@ -23,6 +23,10 @@ module HTTPClientSpecHelper
23
23
  :status => response.code.to_s })
24
24
  end
25
25
 
26
+ def default_client_request_headers(request_method = nil, has_body = false)
27
+ {'Content-Type'=>'application/x-www-form-urlencoded'} if request_method == 'POST' && has_body
28
+ end
29
+
26
30
  def setup_expectations_for_real_request(options = {})
27
31
  socket = mock("TCPSocket")
28
32
  TCPSocket.should_receive(:new).
@@ -29,6 +29,13 @@ describe "Webmock with Net:HTTP" do
29
29
  req.body = "my_params"
30
30
  Net::HTTP.start("www.example.com") { |http| http.request(req)}.body.should == "abc"
31
31
  end
32
+
33
+ it "should handle Net::HTTP::Post#body_stream" do
34
+ stub_http_request(:post, "www.example.com").with(:body => "my_params").to_return(:body => "abc")
35
+ req = Net::HTTP::Post.new("/")
36
+ req.body_stream = StringIO.new("my_params")
37
+ Net::HTTP.start("www.example.com") { |http| http.request(req)}.body.should == "abc"
38
+ end
32
39
 
33
40
  it "should behave like Net::HTTP and raise error if both request body and body argument are set" do
34
41
  stub_http_request(:post, "www.example.com").with(:body => "my_params").to_return(:body => "abc")
@@ -39,4 +46,5 @@ describe "Webmock with Net:HTTP" do
39
46
  }.should raise_error("both of body argument and HTTPRequest#body set")
40
47
  end
41
48
 
49
+
42
50
  end
@@ -16,11 +16,20 @@ module NetHTTPSpecHelper
16
16
  response = http.start {|http|
17
17
  http.request(req, options[:body], &block)
18
18
  }
19
+ headers = {}
20
+ response.each_header {|name, value| headers[name] = value}
19
21
  OpenStruct.new({
20
22
  :body => response.body,
21
- :headers => response,
23
+ :headers => WebMock::Util::Headers.normalize_headers(headers),
22
24
  :status => response.code })
23
25
  end
26
+
27
+ def default_client_request_headers(request_method = nil, has_body = false)
28
+ default_request = Net::HTTPGenericRequest.new('','','','/')
29
+ default_net_http_headers = Hash[*default_request.to_hash.map {|k,v|
30
+ [k, v.flatten]
31
+ }.flatten]
32
+ end
24
33
 
25
34
  # Sets several expectations that a real HTTP request makes it
26
35
  # past WebMock to the socket layer. You can use this when you need to check
@@ -35,6 +35,11 @@ describe RequestProfile do
35
35
  "GET http://www.example.com/ with body 'abc' with headers {'A'=>'a', 'B'=>'b'}"
36
36
  end
37
37
 
38
+ it "should report string describing itself with block" do
39
+ RequestProfile.new(:get, "www.example.com",
40
+ :body => "abc", :headers => {'A' => 'a', 'B' => 'b'}).with {|req| true}.to_s.should ==
41
+ "GET http://www.example.com/ with body 'abc' with headers {'A'=>'a', 'B'=>'b'} with given block"
42
+ end
38
43
 
39
44
  describe "with" do
40
45
  before(:each) do
@@ -50,7 +50,7 @@ describe RequestRegistry do
50
50
  describe "response for request" do
51
51
 
52
52
  it "should registered response for request profile" do
53
- @request_stub.response = @response = Response.new
53
+ @request_stub.instance_variable_set(:@responses, [@response = Response.new])
54
54
  RequestRegistry.instance.register_request_stub(@request_stub)
55
55
  RequestRegistry.instance.response_for_request(@request_signature).should == @response
56
56
  end
@@ -61,11 +61,11 @@ describe RequestRegistry do
61
61
 
62
62
  it "should always return last registered matching response" do
63
63
  @request_stub1 = RequestStub.new(:get, "www.example.com")
64
- @request_stub1.response = @response1 = Response.new
64
+ @request_stub1.instance_variable_set(:@responses, [@response1 = Response.new])
65
65
  @request_stub2 = RequestStub.new(:get, "www.example.com")
66
- @request_stub2.response = @response2 = Response.new
66
+ @request_stub2.instance_variable_set(:@responses, [@response2 = Response.new])
67
67
  @request_stub3 = RequestStub.new(:get, "www.example.org")
68
- @request_stub3.response = @response3 = Response.new
68
+ @request_stub3.instance_variable_set(:@responses, [@response3 = Response.new])
69
69
  RequestRegistry.instance.register_request_stub(@request_stub1)
70
70
  RequestRegistry.instance.register_request_stub(@request_stub2)
71
71
  RequestRegistry.instance.register_request_stub(@request_stub3)
@@ -89,11 +89,21 @@ describe RequestSignature do
89
89
  RequestSignature.new(:get, "www.example.com", :body => "abc").
90
90
  should match(RequestProfile.new(:get, "www.example.com", :body => "abc"))
91
91
  end
92
+
93
+ it "should match for body matching regexp" do
94
+ RequestSignature.new(:get, "www.example.com", :body => "abc").
95
+ should match(RequestProfile.new(:get, "www.example.com", :body => /^abc$/))
96
+ end
92
97
 
93
98
  it "should not match for different bodies" do
94
99
  RequestSignature.new(:get, "www.example.com", :body => "abc").
95
100
  should_not match(RequestProfile.new(:get, "www.example.com", :body => "def"))
96
101
  end
102
+
103
+ it "should not match for body not matching regexp" do
104
+ RequestSignature.new(:get, "www.example.com", :body => "xabc").
105
+ should_not match(RequestProfile.new(:get, "www.example.com", :body => /^abc$/))
106
+ end
97
107
 
98
108
  it "should match if other has not specified body" do
99
109
  RequestSignature.new(:get, "www.example.com", :body => "abc").
@@ -119,11 +129,21 @@ describe RequestSignature do
119
129
  RequestSignature.new(:get, "www.example.com", :headers => {'Content-Type' => 'image/jpeg'}).
120
130
  should match(RequestProfile.new(:get, "www.example.com", :headers => {'Content-Type' => 'image/jpeg'}))
121
131
  end
132
+
133
+ it "should match for header values matching regexp" do
134
+ RequestSignature.new(:get, "www.example.com", :headers => {'Content-Type' => 'image/jpeg'}).
135
+ should match(RequestProfile.new(:get, "www.example.com", :headers => {'Content-Type' => %r{^image/jpeg$}}))
136
+ end
122
137
 
123
138
  it "should not match for different values of the same header" do
124
139
  RequestSignature.new(:get, "www.example.com", :headers => {'Content-Type' => 'image/jpeg'}).
125
140
  should_not match(RequestProfile.new(:get, "www.example.com", :headers => {'Content-Type' => 'image/png'}))
126
141
  end
142
+
143
+ it "should not match for header values not matching regexp" do
144
+ RequestSignature.new(:get, "www.example.com", :headers => {'Content-Type' => 'image/jpegx'}).
145
+ should_not match(RequestProfile.new(:get, "www.example.com", :headers => {'Content-Type' => %r{^image\/jpeg$}}))
146
+ end
127
147
 
128
148
  it "should match if request has more headers than other" do
129
149
  RequestSignature.new(:get, "www.example.com", :headers => {'Content-Type' => 'image/jpeg', 'Content-Length' => '8888'}).
@@ -165,6 +185,21 @@ describe RequestSignature do
165
185
  should_not match(RequestProfile.new(:get, "www.example.com", :headers => {'A'=>'a'}))
166
186
  end
167
187
 
188
+ it "should match if block given to profile evaluates on request to true" do
189
+ RequestSignature.new(:get, "www.example.com").
190
+ should match(RequestProfile.new(:get, "www.example.com").with { |request| true } )
191
+ end
192
+
193
+ it "should not match if block given to profile evaluates on request to false" do
194
+ RequestSignature.new(:get, "www.example.com").
195
+ should_not match( RequestProfile.new(:get, "www.example.com").with { |request| false } )
196
+ end
197
+
198
+ it "should pass self to the block when matching" do
199
+ signature = RequestSignature.new(:get, "www.example.com")
200
+ signature.should match(RequestProfile.new(:get, "www.example.com").with { |request| request == signature } )
201
+ end
202
+
168
203
  end
169
204
 
170
205
  end
@@ -28,6 +28,11 @@ describe RequestStub do
28
28
  @request_stub.request_profile.headers.should == {'B' => 'b'}
29
29
  end
30
30
 
31
+ it "should assign given block to request profile" do
32
+ @request_stub.with { |req| "block output" }
33
+ @request_stub.request_profile.with_block.call(nil).should == "block output"
34
+ end
35
+
31
36
  end
32
37
 
33
38
  describe "to_return" do
@@ -38,6 +43,46 @@ describe RequestStub do
38
43
  @request_stub.response.status.should == 500
39
44
  end
40
45
 
46
+ it "should assign responses with provided options" do
47
+ @request_stub.to_return([{:body => "abc"}, {:body => "def"}])
48
+ [@request_stub.response.body, @request_stub.response.body].should == ["abc", "def"]
49
+ end
50
+
51
+ end
52
+
53
+ describe "then" do
54
+ it "should return stub without any modifications, acting as syntactic sugar" do
55
+ @request_stub.then.should == @request_stub
56
+ end
57
+ end
58
+
59
+ describe "response" do
60
+
61
+ it "should return responses in a sequence passed as array" do
62
+ @request_stub.to_return([{:body => "abc"}, {:body => "def"}])
63
+ @request_stub.response.body.should == "abc"
64
+ @request_stub.response.body.should == "def"
65
+ end
66
+
67
+ it "should repeat returning last response" do
68
+ @request_stub.to_return([{:body => "abc"}, {:body => "def"}])
69
+ @request_stub.response
70
+ @request_stub.response
71
+ @request_stub.response.body.should == "def"
72
+ end
73
+
74
+ it "should return responses in a sequence passed as comma separated params" do
75
+ @request_stub.to_return({:body => "abc"}, {:body => "def"})
76
+ @request_stub.response.body.should == "abc"
77
+ @request_stub.response.body.should == "def"
78
+ end
79
+
80
+ it "should return responses declared in multiple to_return declarations" do
81
+ @request_stub.to_return({:body => "abc"}).to_return({:body => "def"})
82
+ @request_stub.response.body.should == "abc"
83
+ @request_stub.response.body.should == "def"
84
+ end
85
+
41
86
  end
42
87
 
43
88
  describe "to_raise" do
@@ -48,7 +93,85 @@ describe RequestStub do
48
93
  @request_stub.response.raise_error_if_any
49
94
  }.should raise_error(ArgumentError, "Exception from WebMock")
50
95
  end
96
+
97
+ it "should assign sequence of responses with response with exception to be thrown" do
98
+ @request_stub.to_return(:body => "abc").then.to_raise(ArgumentError)
99
+ @request_stub.response.body.should == "abc"
100
+ lambda {
101
+ @request_stub.response.raise_error_if_any
102
+ }.should raise_error(ArgumentError, "Exception from WebMock")
103
+ end
51
104
 
105
+ it "should assign a list responses to be thrown in a sequence" do
106
+ @request_stub.to_raise(ArgumentError, IndexError)
107
+ lambda {
108
+ @request_stub.response.raise_error_if_any
109
+ }.should raise_error(ArgumentError, "Exception from WebMock")
110
+ lambda {
111
+ @request_stub.response.raise_error_if_any
112
+ }.should raise_error(IndexError, "Exception from WebMock")
113
+ end
114
+
115
+ it "should raise exceptions declared in multiple to_raise declarations" do
116
+ @request_stub.to_raise(ArgumentError).then.to_raise(IndexError)
117
+ lambda {
118
+ @request_stub.response.raise_error_if_any
119
+ }.should raise_error(ArgumentError, "Exception from WebMock")
120
+ lambda {
121
+ @request_stub.response.raise_error_if_any
122
+ }.should raise_error(IndexError, "Exception from WebMock")
123
+ end
124
+
125
+ end
126
+
127
+
128
+ describe "times" do
129
+
130
+ it "should give error if declared before any response declaration is declared" do
131
+ lambda {
132
+ @request_stub.times(3)
133
+ }.should raise_error("Invalid WebMock stub declaration. times(N) can be declared only after response declaration.")
134
+ end
135
+
136
+ it "should repeat returning last declared response declared number of times" do
137
+ @request_stub.to_return({:body => "abc"}).times(2).then.to_return({:body => "def"})
138
+ @request_stub.response.body.should == "abc"
139
+ @request_stub.response.body.should == "abc"
140
+ @request_stub.response.body.should == "def"
141
+ end
142
+
143
+ it "should repeat raising last declared exception declared number of times" do
144
+ @request_stub.to_return({:body => "abc"}).times(2).then.to_return({:body => "def"})
145
+ @request_stub.response.body.should == "abc"
146
+ @request_stub.response.body.should == "abc"
147
+ @request_stub.response.body.should == "def"
148
+ end
149
+
150
+ it "should repeat returning last declared sequence of responses declared number of times" do
151
+ @request_stub.to_return({:body => "abc"}, {:body => "def"}).times(2).then.to_return({:body => "ghj"})
152
+ @request_stub.response.body.should == "abc"
153
+ @request_stub.response.body.should == "def"
154
+ @request_stub.response.body.should == "abc"
155
+ @request_stub.response.body.should == "def"
156
+ @request_stub.response.body.should == "ghj"
157
+ end
158
+
159
+ it "should return self" do
160
+ @request_stub.to_return({:body => "abc"}).times(1).should == @request_stub
161
+ end
162
+
163
+ it "should raise error if argument is not integer" do
164
+ lambda {
165
+ @request_stub.to_return({:body => "abc"}).times("not number")
166
+ }.should raise_error("times(N) accepts integers >= 1 only")
167
+ end
168
+
169
+ it "should raise error if argument is < 1" do
170
+ lambda {
171
+ @request_stub.to_return({:body => "abc"}).times(0)
172
+ }.should raise_error("times(N) accepts integers >= 1 only")
173
+ end
174
+
52
175
  end
53
176
 
54
177
  end