arachni-typhoeus 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
+