arachni-typhoeus 0.2.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.
Files changed (55) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGELOG.markdown +43 -0
  3. data/Gemfile +9 -0
  4. data/Gemfile.lock +30 -0
  5. data/README.textile +6 -0
  6. data/Rakefile +40 -0
  7. data/VERSION +1 -0
  8. data/benchmarks/profile.rb +25 -0
  9. data/benchmarks/vs_nethttp.rb +35 -0
  10. data/examples/twitter.rb +21 -0
  11. data/ext/typhoeus/.gitignore +7 -0
  12. data/ext/typhoeus/extconf.rb +65 -0
  13. data/ext/typhoeus/native.c +11 -0
  14. data/ext/typhoeus/native.h +21 -0
  15. data/ext/typhoeus/typhoeus_easy.c +220 -0
  16. data/ext/typhoeus/typhoeus_easy.h +19 -0
  17. data/ext/typhoeus/typhoeus_multi.c +211 -0
  18. data/ext/typhoeus/typhoeus_multi.h +16 -0
  19. data/lib/typhoeus.rb +58 -0
  20. data/lib/typhoeus/.gitignore +1 -0
  21. data/lib/typhoeus/easy.rb +366 -0
  22. data/lib/typhoeus/filter.rb +28 -0
  23. data/lib/typhoeus/hydra.rb +245 -0
  24. data/lib/typhoeus/hydra/callbacks.rb +24 -0
  25. data/lib/typhoeus/hydra/connect_options.rb +61 -0
  26. data/lib/typhoeus/hydra/stubbing.rb +52 -0
  27. data/lib/typhoeus/hydra_mock.rb +131 -0
  28. data/lib/typhoeus/multi.rb +37 -0
  29. data/lib/typhoeus/normalized_header_hash.rb +58 -0
  30. data/lib/typhoeus/remote.rb +306 -0
  31. data/lib/typhoeus/remote_method.rb +108 -0
  32. data/lib/typhoeus/remote_proxy_object.rb +50 -0
  33. data/lib/typhoeus/request.rb +210 -0
  34. data/lib/typhoeus/response.rb +91 -0
  35. data/lib/typhoeus/service.rb +20 -0
  36. data/lib/typhoeus/utils.rb +24 -0
  37. data/profilers/valgrind.rb +24 -0
  38. data/spec/fixtures/result_set.xml +60 -0
  39. data/spec/servers/app.rb +84 -0
  40. data/spec/spec.opts +2 -0
  41. data/spec/spec_helper.rb +11 -0
  42. data/spec/typhoeus/easy_spec.rb +284 -0
  43. data/spec/typhoeus/filter_spec.rb +35 -0
  44. data/spec/typhoeus/hydra_mock_spec.rb +300 -0
  45. data/spec/typhoeus/hydra_spec.rb +526 -0
  46. data/spec/typhoeus/multi_spec.rb +74 -0
  47. data/spec/typhoeus/normalized_header_hash_spec.rb +41 -0
  48. data/spec/typhoeus/remote_method_spec.rb +141 -0
  49. data/spec/typhoeus/remote_proxy_object_spec.rb +65 -0
  50. data/spec/typhoeus/remote_spec.rb +695 -0
  51. data/spec/typhoeus/request_spec.rb +276 -0
  52. data/spec/typhoeus/response_spec.rb +151 -0
  53. data/spec/typhoeus/utils_spec.rb +22 -0
  54. data/typhoeus.gemspec +123 -0
  55. metadata +196 -0
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'sinatra'
4
+ require 'json'
5
+ require 'zlib'
6
+
7
+ @@fail_count = 0
8
+ get '/fail/:number' do
9
+ if @@fail_count >= params[:number].to_i
10
+ "ok"
11
+ else
12
+ @@fail_count += 1
13
+ error 500, "oh noes!"
14
+ end
15
+ end
16
+
17
+ get '/fail_forever' do
18
+ error 500, "oh noes!"
19
+ end
20
+
21
+ get '/redirect' do
22
+ redirect '/'
23
+ end
24
+
25
+ get '/bad_redirect' do
26
+ redirect '/bad_redirect'
27
+ end
28
+
29
+ get '/auth_basic/:username/:password' do
30
+ @auth ||= Rack::Auth::Basic::Request.new(request.env)
31
+ # Check that we've got a basic auth, and that it's credentials match the ones
32
+ # provided in the request
33
+ if @auth.provided? && @auth.basic? && @auth.credentials == [ params[:username], params[:password] ]
34
+ # auth is valid - confirm it
35
+ true
36
+ else
37
+ # invalid auth - request the authentication
38
+ response['WWW-Authenticate'] = %(Basic realm="Testing HTTP Auth")
39
+ throw(:halt, [401, "Not authorized\n"])
40
+ end
41
+ end
42
+
43
+ get '/auth_ntlm' do
44
+ # we're just checking for the existence if NTLM auth header here. It's validation
45
+ # is too troublesome and really doesn't bother is much, it's up to libcurl to make
46
+ # it valid
47
+ response['WWW-Authenticate'] = 'NTLM'
48
+ is_ntlm_auth = /^NTLM/ =~ request.env['HTTP_AUTHORIZATION']
49
+ true if is_ntlm_auth
50
+ throw(:halt, [401, "Not authorized\n"]) if !is_ntlm_auth
51
+ end
52
+
53
+ get '/gzipped' do
54
+ req_env = request.env.to_json
55
+ z = Zlib::Deflate.new
56
+ gzipped_env = z.deflate(req_env, Zlib::FINISH)
57
+ z.close
58
+ response['Content-Encoding'] = 'gzip'
59
+ gzipped_env
60
+ end
61
+
62
+ get '/**' do
63
+ sleep params["delay"].to_i if params.has_key?("delay")
64
+ request.env.merge!(:body => request.body.read).to_json
65
+ end
66
+
67
+ head '/**' do
68
+ sleep params["delay"].to_i if params.has_key?("delay")
69
+ end
70
+
71
+ put '/**' do
72
+ puts request.inspect
73
+ request.env.merge!(:body => request.body.read).to_json
74
+ end
75
+
76
+ post '/**' do
77
+ puts request.inspect
78
+ request.env.merge!(:body => request.body.read).to_json
79
+ end
80
+
81
+ delete '/**' do
82
+ puts request.inspect
83
+ request.env.merge!(:body => request.body.read).to_json
84
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --diff
2
+ --color
@@ -0,0 +1,11 @@
1
+ require "rubygems"
2
+ require 'json'
3
+ require "spec"
4
+
5
+ # gem install redgreen for colored test output
6
+ begin require "redgreen" unless ENV['TM_CURRENT_LINE']; rescue LoadError; end
7
+
8
+ path = File.expand_path(File.dirname(__FILE__) + "/../lib/")
9
+ $LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
10
+
11
+ require path + '/typhoeus'
@@ -0,0 +1,284 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Typhoeus::Easy do
4
+ describe "#supports_zlib" do
5
+ before(:each) do
6
+ @easy = Typhoeus::Easy.new
7
+ end
8
+
9
+ it "should return true if the version string has zlib" do
10
+ @easy.stub!(:curl_version).and_return("libcurl/7.20.0 OpenSSL/0.9.8l zlib/1.2.3 libidn/1.16")
11
+ @easy.supports_zlib?.should be_true
12
+ end
13
+
14
+ it "should return false if the version string doesn't have zlib" do
15
+ @easy.stub!(:curl_version).and_return("libcurl/7.20.0 OpenSSL/0.9.8l libidn/1.16")
16
+ @easy.supports_zlib?.should be_false
17
+ end
18
+ end
19
+
20
+ describe "curl errors" do
21
+ it "should provide the CURLE_OPERATION_TIMEDOUT return code when a request times out" do
22
+ e = Typhoeus::Easy.new
23
+ e.url = "http://localhost:3001/?delay=1"
24
+ e.method = :get
25
+ e.timeout = 100
26
+ e.perform
27
+ e.curl_return_code.should == 28
28
+ e.curl_error_message.should == "Timeout was reached"
29
+ e.response_code.should == 0
30
+ end
31
+
32
+ it "should provide the CURLE_COULDNT_CONNECT return code when trying to connect to a non existent port" do
33
+ e = Typhoeus::Easy.new
34
+ e.url = "http://localhost:3999"
35
+ e.method = :get
36
+ e.connect_timeout = 100
37
+ e.perform
38
+ e.curl_return_code.should == 7
39
+ e.curl_error_message.should == "Couldn't connect to server"
40
+ e.response_code.should == 0
41
+ end
42
+
43
+ it "should not return an error message on a successful easy operation" do
44
+ easy = Typhoeus::Easy.new
45
+ easy.url = "http://localhost:3002"
46
+ easy.method = :get
47
+ easy.curl_error_message.should == nil
48
+ easy.perform
49
+ easy.response_code.should == 200
50
+ easy.curl_return_code.should == 0
51
+ easy.curl_error_message.should == "No error"
52
+ end
53
+
54
+ end
55
+
56
+ describe "options" do
57
+ it "should not follow redirects if not instructed to" do
58
+ e = Typhoeus::Easy.new
59
+ e.url = "http://localhost:3001/redirect"
60
+ e.method = :get
61
+ e.perform
62
+ e.response_code.should == 302
63
+ end
64
+
65
+ it "should allow for following redirects" do
66
+ e = Typhoeus::Easy.new
67
+ e.url = "http://localhost:3001/redirect"
68
+ e.method = :get
69
+ e.follow_location = true
70
+ e.perform
71
+ e.response_code.should == 200
72
+ JSON.parse(e.response_body)["REQUEST_METHOD"].should == "GET"
73
+ end
74
+
75
+ it "should allow you to set the user agent" do
76
+ easy = Typhoeus::Easy.new
77
+ easy.url = "http://localhost:3002"
78
+ easy.method = :get
79
+ easy.user_agent = "myapp"
80
+ easy.perform
81
+ easy.response_code.should == 200
82
+ JSON.parse(easy.response_body)["HTTP_USER_AGENT"].should == "myapp"
83
+ end
84
+
85
+ it "should provide a timeout in milliseconds" do
86
+ e = Typhoeus::Easy.new
87
+ e.url = "http://localhost:3001/?delay=1"
88
+ e.method = :get
89
+ e.timeout = 10
90
+ e.perform
91
+ e.timed_out?.should == true
92
+ end
93
+
94
+ it "should allow the setting of the max redirects to follow" do
95
+ e = Typhoeus::Easy.new
96
+ e.url = "http://localhost:3001/redirect"
97
+ e.method = :get
98
+ e.follow_location = true
99
+ e.max_redirects = 5
100
+ e.perform
101
+ e.response_code.should == 200
102
+ end
103
+
104
+ it "should handle our bad redirect action, provided we've set max_redirects properly" do
105
+ e = Typhoeus::Easy.new
106
+ e.url = "http://localhost:3001/bad_redirect"
107
+ e.method = :get
108
+ e.follow_location = true
109
+ e.max_redirects = 5
110
+ e.perform
111
+ e.response_code.should == 302
112
+ end
113
+ end
114
+
115
+ describe "authentication" do
116
+ it "should allow to set username and password" do
117
+ e = Typhoeus::Easy.new
118
+ username, password = 'foo', 'bar'
119
+ e.auth = { :username => username, :password => password }
120
+ e.url = "http://localhost:3001/auth_basic/#{username}/#{password}"
121
+ e.method = :get
122
+ e.perform
123
+ e.response_code.should == 200
124
+ end
125
+
126
+ it "should allow to query auth methods support by the server" do
127
+ e = Typhoeus::Easy.new
128
+ e.url = "http://localhost:3001/auth_basic/foo/bar"
129
+ e.method = :get
130
+ e.perform
131
+ e.auth_methods.should == Typhoeus::Easy::AUTH_TYPES[:CURLAUTH_BASIC]
132
+ end
133
+
134
+ it "should allow to set authentication method" do
135
+ e = Typhoeus::Easy.new
136
+ e.auth = { :username => 'username', :password => 'password', :method => Typhoeus::Easy::AUTH_TYPES[:CURLAUTH_NTLM] }
137
+ e.url = "http://localhost:3001/auth_ntlm"
138
+ e.method = :get
139
+ e.perform
140
+ e.response_code.should == 200
141
+ end
142
+ end
143
+
144
+ describe "get" do
145
+ it "should perform a get" do
146
+ easy = Typhoeus::Easy.new
147
+ easy.url = "http://localhost:3002"
148
+ easy.method = :get
149
+ easy.perform
150
+ easy.response_code.should == 200
151
+ JSON.parse(easy.response_body)["REQUEST_METHOD"].should == "GET"
152
+ end
153
+ end
154
+
155
+ describe "purge" do
156
+ it "should set custom request to purge" do
157
+ easy = Typhoeus::Easy.new
158
+ easy.should_receive(:set_option).with(Typhoeus::Easy::OPTION_VALUES[:CURLOPT_CUSTOMREQUEST], "PURGE").once
159
+ easy.method = :purge
160
+ end
161
+ end
162
+
163
+ describe "head" do
164
+ it "should perform a head" do
165
+ easy = Typhoeus::Easy.new
166
+ easy.url = "http://localhost:3002"
167
+ easy.method = :head
168
+ easy.perform
169
+ easy.response_code.should == 200
170
+ end
171
+ end
172
+
173
+ describe "start_time" do
174
+ it "should be get/settable" do
175
+ time = Time.now
176
+ easy = Typhoeus::Easy.new
177
+ easy.start_time.should be_nil
178
+ easy.start_time = time
179
+ easy.start_time.should == time
180
+ end
181
+ end
182
+
183
+ describe "params=" do
184
+ it "should handle arrays of params" do
185
+ easy = Typhoeus::Easy.new
186
+ easy.url = "http://localhost:3002/index.html"
187
+ easy.method = :get
188
+ easy.request_body = "this is a body!"
189
+ easy.params = {
190
+ :foo => 'bar',
191
+ :username => ['dbalatero', 'dbalatero2']
192
+ }
193
+
194
+ easy.url.should =~ /\?.*username=dbalatero&username=dbalatero2/
195
+ end
196
+ end
197
+
198
+
199
+ describe "put" do
200
+ it "should perform a put" do
201
+ easy = Typhoeus::Easy.new
202
+ easy.url = "http://localhost:3002"
203
+ easy.method = :put
204
+ easy.perform
205
+ easy.response_code.should == 200
206
+ JSON.parse(easy.response_body)["REQUEST_METHOD"].should == "PUT"
207
+ end
208
+
209
+ it "should send a request body" do
210
+ easy = Typhoeus::Easy.new
211
+ easy.url = "http://localhost:3002"
212
+ easy.method = :put
213
+ easy.request_body = "this is a body!"
214
+ easy.perform
215
+ easy.response_code.should == 200
216
+ easy.response_body.should include("this is a body!")
217
+ end
218
+ end
219
+
220
+ describe "post" do
221
+ it "should perform a post" do
222
+ easy = Typhoeus::Easy.new
223
+ easy.url = "http://localhost:3002"
224
+ easy.method = :post
225
+ easy.perform
226
+ easy.response_code.should == 200
227
+ JSON.parse(easy.response_body)["REQUEST_METHOD"].should == "POST"
228
+ end
229
+
230
+ it "should send a request body" do
231
+ easy = Typhoeus::Easy.new
232
+ easy.url = "http://localhost:3002"
233
+ easy.method = :post
234
+ easy.request_body = "this is a body!"
235
+ easy.perform
236
+ easy.response_code.should == 200
237
+ easy.response_body.should include("this is a body!")
238
+ end
239
+
240
+ it "should handle params" do
241
+ easy = Typhoeus::Easy.new
242
+ easy.url = "http://localhost:3002"
243
+ easy.method = :post
244
+ easy.params = {:foo => "bar"}
245
+ easy.perform
246
+ easy.response_code.should == 200
247
+ easy.response_body.should include("foo=bar")
248
+ end
249
+ end
250
+
251
+ describe "delete" do
252
+ it "should perform a delete" do
253
+ easy = Typhoeus::Easy.new
254
+ easy.url = "http://localhost:3002"
255
+ easy.method = :delete
256
+ easy.perform
257
+ easy.response_code.should == 200
258
+ JSON.parse(easy.response_body)["REQUEST_METHOD"].should == "DELETE"
259
+ end
260
+
261
+ it "should send a request body" do
262
+ easy = Typhoeus::Easy.new
263
+ easy.url = "http://localhost:3002"
264
+ easy.method = :delete
265
+ easy.request_body = "this is a body!"
266
+ easy.perform
267
+ easy.response_code.should == 200
268
+ easy.response_body.should include("this is a body!")
269
+ end
270
+ end
271
+
272
+ describe "encoding/compression support" do
273
+
274
+ it "should send valid encoding headers and decode the response" do
275
+ easy = Typhoeus::Easy.new
276
+ easy.url = "http://localhost:3002/gzipped"
277
+ easy.method = :get
278
+ easy.perform
279
+ easy.response_code.should == 200
280
+ JSON.parse(easy.response_body)["HTTP_ACCEPT_ENCODING"].should == "deflate, gzip"
281
+ end
282
+
283
+ end
284
+ end
@@ -0,0 +1,35 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Typhoeus::Filter do
4
+ it "should take a method name and optionally take options" do
5
+ filter = Typhoeus::Filter.new(:bar, :only => :foo)
6
+ filter = Typhoeus::Filter.new(:bar)
7
+ end
8
+
9
+ describe "#apply_filter?" do
10
+ it "should return true for any method when :only and :except aren't specified" do
11
+ filter = Typhoeus::Filter.new(:bar)
12
+ filter.apply_filter?(:asdf).should be_true
13
+ end
14
+
15
+ it "should return true if a method is in only" do
16
+ filter = Typhoeus::Filter.new(:bar, :only => :foo)
17
+ filter.apply_filter?(:foo).should be_true
18
+ end
19
+
20
+ it "should return false if a method isn't in only" do
21
+ filter = Typhoeus::Filter.new(:bar, :only => :foo)
22
+ filter.apply_filter?(:bar).should be_false
23
+ end
24
+
25
+ it "should return true if a method isn't in except" do
26
+ filter = Typhoeus::Filter.new(:bar, :except => :foo)
27
+ filter.apply_filter?(:bar).should be_true
28
+ end
29
+
30
+ it "should return false if a method is in except" do
31
+ filter = Typhoeus::Filter.new(:bar, :except => :foo)
32
+ filter.apply_filter?(:foo).should be_false
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,300 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Typhoeus::HydraMock do
4
+ it "should mark all responses as mocks" do
5
+ response = Typhoeus::Response.new(:mock => false)
6
+ response.should_not be_mock
7
+
8
+ mock = Typhoeus::HydraMock.new("http://localhost", :get)
9
+ mock.and_return(response)
10
+
11
+ mock.response.should be_mock
12
+ response.should be_mock
13
+ end
14
+
15
+ describe "stubbing response values" do
16
+ before(:each) do
17
+ @stub = Typhoeus::HydraMock.new('http://localhost:3000', :get)
18
+ end
19
+
20
+ describe "with a single response" do
21
+ it "should always return that response" do
22
+ response = Typhoeus::Response.new
23
+ @stub.and_return(response)
24
+
25
+ 5.times do
26
+ @stub.response.should == response
27
+ end
28
+ end
29
+ end
30
+
31
+ describe "with multiple responses" do
32
+ it "should return consecutive responses in the array, then keep returning the last one" do
33
+ responses = []
34
+ 3.times do |i|
35
+ responses << Typhoeus::Response.new(:body => "response #{i}")
36
+ end
37
+
38
+ # Stub 3 consecutive responses.
39
+ @stub.and_return(responses)
40
+
41
+ 0.upto(2) do |i|
42
+ @stub.response.should == responses[i]
43
+ end
44
+
45
+ 5.times do
46
+ @stub.response.should == responses.last
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ describe "#matches?" do
53
+ describe "basic matching" do
54
+ it "should not match if the HTTP verbs are different" do
55
+ request = Typhoeus::Request.new("http://localhost:3000",
56
+ :method => :get)
57
+ mock = Typhoeus::HydraMock.new("http://localhost:3000", :post)
58
+ mock.matches?(request).should be_false
59
+ end
60
+ end
61
+
62
+ describe "matching on ports" do
63
+ it "should handle default port 80 sanely" do
64
+ mock = Typhoeus::HydraMock.new('http://www.example.com:80/', :get,
65
+ :headers => { 'user-agent' => 'test' })
66
+ request = Typhoeus::Request.new('http://www.example.com/',
67
+ :method => :get,
68
+ :user_agent => 'test')
69
+ mock.matches?(request).should be_true
70
+ end
71
+
72
+ it "should handle default port 443 sanely" do
73
+ mock = Typhoeus::HydraMock.new('https://www.example.com:443/', :get,
74
+ :headers => { 'user-agent' => 'test' })
75
+ request = Typhoeus::Request.new('https://www.example.com/',
76
+ :method => :get,
77
+ :user_agent => 'test')
78
+ mock.matches?(request).should be_true
79
+ end
80
+ end
81
+
82
+
83
+ describe "any HTTP verb" do
84
+ it "should match any verb" do
85
+ mock = Typhoeus::HydraMock.new("http://localhost:3000", :any,
86
+ :headers => { 'user-agent' => 'test' })
87
+ [:get, :post, :delete, :put].each do |verb|
88
+ request = Typhoeus::Request.new("http://localhost:3000",
89
+ :method => verb,
90
+ :user_agent => 'test')
91
+ mock.matches?(request).should be_true
92
+ end
93
+ end
94
+ end
95
+
96
+ describe "header matching" do
97
+ def request(options = {})
98
+ Typhoeus::Request.new("http://localhost:3000", options.merge(:method => :get))
99
+ end
100
+
101
+ def mock(options = {})
102
+ Typhoeus::HydraMock.new("http://localhost:3000", :get, options)
103
+ end
104
+
105
+ context 'when no :headers option is given' do
106
+ subject { mock }
107
+
108
+ it "matches regardless of whether or not the request has headers" do
109
+ subject.matches?(request(:headers => nil)).should be_true
110
+ subject.matches?(request(:headers => {})).should be_true
111
+ subject.matches?(request(:headers => { 'a' => 'b' })).should be_true
112
+ end
113
+ end
114
+
115
+ [nil, {}].each do |value|
116
+ context "for :headers => #{value.inspect}" do
117
+ subject { mock(:headers => value) }
118
+
119
+ it "matches when the request has no headers" do
120
+ subject.matches?(request(:headers => nil)).should be_true
121
+ subject.matches?(request(:headers => {})).should be_true
122
+ end
123
+
124
+ it "does not match when the request has headers" do
125
+ subject.matches?(request(:headers => { 'a' => 'b' })).should be_false
126
+ end
127
+ end
128
+ end
129
+
130
+ context 'for :headers => [a hash]' do
131
+ it 'does not match if the request has no headers' do
132
+ m = mock(:headers => { 'A' => 'B', 'C' => 'D' })
133
+
134
+ m.matches?(request).should be_false
135
+ m.matches?(request(:headers => nil)).should be_false
136
+ m.matches?(request(:headers => {})).should be_false
137
+ end
138
+
139
+ it 'does not match if the request lacks any of the given headers' do
140
+ mock(
141
+ :headers => { 'A' => 'B', 'C' => 'D' }
142
+ ).matches?(request(
143
+ :headers => { 'A' => 'B' }
144
+ )).should be_false
145
+ end
146
+
147
+ it 'does not match if any of the specified values are different from the request value' do
148
+ mock(
149
+ :headers => { 'A' => 'B', 'C' => 'D' }
150
+ ).matches?(request(
151
+ :headers => { 'A' => 'B', 'C' => 'E' }
152
+ )).should be_false
153
+ end
154
+
155
+ it 'matches if the given hash is exactly equal to the request headers' do
156
+ mock(
157
+ :headers => { 'A' => 'B', 'C' => 'D' }
158
+ ).matches?(request(
159
+ :headers => { 'A' => 'B', 'C' => 'D' }
160
+ )).should be_true
161
+ end
162
+
163
+ it 'matches even if the request has additional headers not specified in the mock' do
164
+ mock(
165
+ :headers => { 'A' => 'B', 'C' => 'D' }
166
+ ).matches?(request(
167
+ :headers => { 'A' => 'B', 'C' => 'D', 'E' => 'F' }
168
+ )).should be_true
169
+ end
170
+
171
+ it 'matches even if the casing of the header keys is different between the mock and request' do
172
+ mock(
173
+ :headers => { 'A' => 'B', 'c' => 'D' }
174
+ ).matches?(request(
175
+ :headers => { 'a' => 'B', 'C' => 'D' }
176
+ )).should be_true
177
+ end
178
+
179
+ it 'matches if the mocked values are regexes and match the request values' do
180
+ mock(
181
+ :headers => { 'A' => /foo/, }
182
+ ).matches?(request(
183
+ :headers => { 'A' => 'foo bar' }
184
+ )).should be_true
185
+ end
186
+
187
+ it 'does not match if the mocked values are regexes and do not match the request values' do
188
+ mock(
189
+ :headers => { 'A' => /foo/, }
190
+ ).matches?(request(
191
+ :headers => { 'A' => 'bar' }
192
+ )).should be_false
193
+ end
194
+
195
+ context 'when a header is specified as an array' do
196
+ it 'matches when the request header has the same array' do
197
+ mock(
198
+ :headers => { 'Accept' => ['text/html', 'text/plain'] }
199
+ ).matches?(request(
200
+ :headers => { 'Accept' => ['text/html', 'text/plain'] }
201
+ )).should be_true
202
+ end
203
+
204
+ it 'matches when the request header is a single value and the mock array has the same value' do
205
+ mock(
206
+ :headers => { 'Accept' => ['text/html'] }
207
+ ).matches?(request(
208
+ :headers => { 'Accept' => 'text/html' }
209
+ )).should be_true
210
+ end
211
+
212
+ it 'matches even when the request header array is ordered differently' do
213
+ mock(
214
+ :headers => { 'Accept' => ['text/html', 'text/plain'] }
215
+ ).matches?(request(
216
+ :headers => { 'Accept' => ['text/plain', 'text/html'] }
217
+ )).should be_true
218
+ end
219
+
220
+ it 'does not match when the request header array lacks a value' do
221
+ mock(
222
+ :headers => { 'Accept' => ['text/html', 'text/plain'] }
223
+ ).matches?(request(
224
+ :headers => { 'Accept' => ['text/plain'] }
225
+ )).should be_false
226
+ end
227
+
228
+ it 'does not match when the request header array has an extra value' do
229
+ mock(
230
+ :headers => { 'Accept' => ['text/html', 'text/plain'] }
231
+ ).matches?(request(
232
+ :headers => { 'Accept' => ['text/html', 'text/plain', 'application/xml'] }
233
+ )).should be_false
234
+ end
235
+
236
+ it 'does not match when the request header is not an array' do
237
+ mock(
238
+ :headers => { 'Accept' => ['text/html', 'text/plain'] }
239
+ ).matches?(request(
240
+ :headers => { 'Accept' => 'text/html' }
241
+ )).should be_false
242
+ end
243
+ end
244
+ end
245
+ end
246
+
247
+ describe "post body matching" do
248
+ it "should not bother matching on body if we don't turn the option on" do
249
+ request = Typhoeus::Request.new("http://localhost:3000",
250
+ :method => :get,
251
+ :user_agent => 'test',
252
+ :body => "fdsafdsa")
253
+ mock = Typhoeus::HydraMock.new("http://localhost:3000", :get,
254
+ :headers => { 'user-agent' => 'test' })
255
+ mock.matches?(request).should be_true
256
+ end
257
+
258
+ it "should match nil correctly" do
259
+ request = Typhoeus::Request.new("http://localhost:3000",
260
+ :method => :get,
261
+ :body => "fdsafdsa")
262
+ mock = Typhoeus::HydraMock.new("http://localhost:3000", :get,
263
+ :body => nil)
264
+ mock.matches?(request).should be_false
265
+ end
266
+
267
+ it "should not match if the bodies do not match" do
268
+ request = Typhoeus::Request.new("http://localhost:3000",
269
+ :method => :get,
270
+ :body => "ffdsadsafdsa")
271
+ mock = Typhoeus::HydraMock.new("http://localhost:3000", :get,
272
+ :body => 'fdsafdsa')
273
+ mock.matches?(request).should be_false
274
+ end
275
+
276
+ it "should match on optional body parameter" do
277
+ request = Typhoeus::Request.new("http://localhost:3000",
278
+ :method => :get,
279
+ :user_agent => 'test',
280
+ :body => "fdsafdsa")
281
+ mock = Typhoeus::HydraMock.new("http://localhost:3000", :get,
282
+ :body => 'fdsafdsa',
283
+ :headers => {
284
+ 'User-Agent' => 'test'
285
+ })
286
+ mock.matches?(request).should be_true
287
+ end
288
+
289
+ it "should regex match" do
290
+ request = Typhoeus::Request.new("http://localhost:3000/whatever/fdsa",
291
+ :method => :get,
292
+ :user_agent => 'test')
293
+ mock = Typhoeus::HydraMock.new(/fdsa/, :get,
294
+ :headers => { 'user-agent' => 'test' })
295
+ mock.matches?(request).should be_true
296
+ end
297
+ end
298
+ end
299
+ end
300
+