dkubb-fakeweb 1.1.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rcov/rcovtask'
5
+
6
+ task :default => :test
7
+
8
+ desc "Run All Tests"
9
+ Rake::TestTask.new :test do |test|
10
+ test.test_files = ["test/**/*.rb"]
11
+ test.verbose = true
12
+ end
13
+
14
+ desc "Generate Documentation"
15
+ Rake::RDocTask.new do |rdoc|
16
+ rdoc.main = "README.rdoc"
17
+ rdoc.rdoc_dir = "doc"
18
+ rdoc.rdoc_files.include("README.rdoc", "CHANGELOG", "LICENSE.txt", "lib/*.rb")
19
+ rdoc.title = "FakeWeb API Documentation"
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.options << '--charset' << 'utf-8'
22
+ end
23
+
24
+ Rcov::RcovTask.new do |t|
25
+ t.test_files = FileList['test/**/test*.rb']
26
+ t.rcov_opts << "--sort coverage"
27
+ t.rcov_opts << "--exclude gems"
28
+ t.rcov_opts << "--no-validator-links"
29
+ end
30
+
31
+ desc %{Update ".manifest" with the latest list of project filenames. Respect\
32
+ .gitignore by excluding everything that git ignores. Update `files` and\
33
+ `test_files` arrays in "*.gemspec" file if it's present.}
34
+ task :manifest do
35
+ list = Dir['**/*'].sort
36
+ spec_file = Dir['*.gemspec'].first
37
+ list -= [spec_file] if spec_file
38
+
39
+ File.read('.gitignore').each_line do |glob|
40
+ glob = glob.chomp.sub(/^\//, '')
41
+ list -= Dir[glob]
42
+ list -= Dir["#{glob}/**/*"] if File.directory?(glob) and !File.symlink?(glob)
43
+ puts "excluding #{glob}"
44
+ end
45
+
46
+ if spec_file
47
+ spec = File.read spec_file
48
+ spec.gsub! /^(\s* s.(test_)?files \s* = \s* )( \[ [^\]]* \] | %w\( [^)]* \) )/mx do
49
+ assignment = $1
50
+ bunch = $2 ? list.grep(/^test\//) : list
51
+ '%s%%w(%s)' % [assignment, bunch.join(' ')]
52
+ end
53
+
54
+ File.open(spec_file, 'w') {|f| f << spec }
55
+ end
56
+ File.open('.manifest', 'w') {|f| f << list.join("\n") }
57
+ end
@@ -0,0 +1,67 @@
1
+ # FakeWeb - Ruby Helper for Faking Web Requests
2
+ # Copyright 2006 Blaine Cook <romeda@gmail.com>.
3
+ #
4
+ # FakeWeb is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # FakeWeb is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with FakeWeb; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ require 'rubygems'
19
+ gem 'httpclient', '>=2.1.2'
20
+ require 'httpclient'
21
+
22
+ class HTTPClient
23
+
24
+ LIBRARY_IDENTIFIER = :httpclient
25
+ FakeWeb.register_client_library(LIBRARY_IDENTIFIER)
26
+
27
+ alias :original_httpclient_do_get_block :do_get_block
28
+
29
+ def self.socket_type
30
+ FakeWeb::SocketDelegator
31
+ end
32
+
33
+ def do_get_block(req, proxy, conn, &block)
34
+ method = req.header.request_method.downcase.to_sym
35
+ uri = req.header.request_uri
36
+
37
+ if FakeWeb.registered_uri?(method, uri)
38
+ message = FakeWeb.response_for(method, LIBRARY_IDENTIFIER, uri, &block)
39
+ conn.push(message)
40
+ elsif FakeWeb.allow_net_connect?
41
+ original_httpclient_do_get_block(req, proxy, conn, &block)
42
+ else
43
+ raise FakeWeb::NetConnectNotAllowedError,
44
+ "Real HTTP connections are disabled. Unregistered request: #{req.header.request_method} #{uri}"
45
+ end
46
+ end
47
+
48
+ =begin
49
+ # Do we want this? I'd imagine it'd make unregistered urls unhappy...
50
+
51
+ # Make sure there's no chance of a connection being made
52
+ class Session
53
+ def query(req)
54
+ end
55
+ end
56
+ =end
57
+
58
+ end
59
+
60
+ # A uniform way to get fake content, for testing.
61
+ module HTTP
62
+ class Message
63
+ def get_content
64
+ self.body.content
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,67 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'stringio'
4
+
5
+ module Net #:nodoc: all
6
+
7
+ class BufferedIO
8
+ def initialize(io, debug_output = nil)
9
+ @read_timeout = 60
10
+ @rbuf = ''
11
+ @debug_output = debug_output
12
+
13
+ @io = case io
14
+ when Socket, OpenSSL::SSL::SSLSocket, IO
15
+ io
16
+ when String
17
+ File.exists?(io) ? File.open(io, "r") : StringIO.new(io)
18
+ end
19
+ raise "Unable to create local socket" unless @io
20
+ end
21
+ end
22
+
23
+
24
+ class HTTP
25
+
26
+ LIBRARY_IDENTIFIER = :net_http
27
+ FakeWeb.register_client_library(LIBRARY_IDENTIFIER)
28
+
29
+ def self.socket_type
30
+ FakeWeb::SocketDelegator
31
+ end
32
+
33
+ alias :original_net_http_request :request
34
+ alias :original_net_http_connect :connect
35
+
36
+ def request(request, body = nil, &block)
37
+ protocol = use_ssl ? "https" : "http"
38
+
39
+ path = request.path
40
+ path = URI.parse(request.path).request_uri if request.path =~ /^http/
41
+
42
+ uri = "#{protocol}://#{self.address}:#{self.port}#{path}"
43
+ method = request.method.downcase.to_sym
44
+
45
+ if FakeWeb.registered_uri?(method, uri)
46
+ @socket = Net::HTTP.socket_type.new
47
+ FakeWeb.response_for(method, LIBRARY_IDENTIFIER, uri, &block)
48
+ elsif FakeWeb.allow_net_connect?
49
+ original_net_http_connect
50
+ original_net_http_request(request, body, &block)
51
+ else
52
+ raise FakeWeb::NetConnectNotAllowedError,
53
+ "Real HTTP connections are disabled. Unregistered request: #{request.method} #{uri}"
54
+ end
55
+ end
56
+
57
+ def connect
58
+ end
59
+ end
60
+
61
+ # A uniform way to get fake content, for testing.
62
+ class HTTPResponse
63
+ def get_content
64
+ self.body
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,348 @@
1
+ module FakeWeb
2
+ CLIENT_LIBRARIES = []
3
+ def self.register_client_library(library_identifier)
4
+ CLIENT_LIBRARIES << library_identifier
5
+ end
6
+ end
7
+
8
+ require File.expand_path(File.join(File.dirname(__FILE__), 'fake_net_http'))
9
+ require File.expand_path(File.join(File.dirname(__FILE__), 'fake_httpclient'))
10
+ require 'singleton'
11
+
12
+ module OpenURI #:nodoc: all
13
+ class HTTPError < StandardError; end;
14
+ end
15
+
16
+ module FakeWeb
17
+
18
+
19
+ # Resets the FakeWeb Registry. This will force all subsequent web requests to
20
+ # behave as real requests.
21
+ def self.clean_registry
22
+ Registry.instance.clean_registry
23
+ end
24
+
25
+ # Enables or disables real HTTP connections for requests that don't match
26
+ # registered URIs.
27
+ #
28
+ # If you set <tt>FakeWeb.allow_net_connect = false</tt> and subsequently try
29
+ # to make a request to a URI you haven't registered with #register_uri, a
30
+ # NetConnectNotAllowedError will be raised. This is handy when you want to
31
+ # make sure your tests are self-contained, or want to catch the scenario
32
+ # when a URI is changed in implementation code without a corresponding test
33
+ # change.
34
+ #
35
+ # When <tt>FakeWeb.allow_net_connect = true</tt> (the default), requests to
36
+ # URIs not stubbed with FakeWeb are passed through to Net::HTTP.
37
+ def self.allow_net_connect=(allowed)
38
+ @allow_net_connect = allowed
39
+ end
40
+
41
+ # Enable pass-through to Net::HTTP by default.
42
+ self.allow_net_connect = true
43
+
44
+ # Returns +true+ if requests to URIs not registered with FakeWeb are passed
45
+ # through to Net::HTTP for normal processing (the default). Returns +false+
46
+ # if an exception is raised for these requests.
47
+ def self.allow_net_connect?
48
+ @allow_net_connect
49
+ end
50
+
51
+ # This exception is raised if you set <tt>FakeWeb.allow_net_connect =
52
+ # false</tt> and subsequently try to make a request to a URI you haven't
53
+ # stubbed.
54
+ class NetConnectNotAllowedError < StandardError; end;
55
+
56
+ # call-seq:
57
+ # FakeWeb.register_uri(method, uri, options)
58
+ # FakeWeb.register_uri(uri, options)
59
+ #
60
+ # Register requests using the HTTP method specified by the symbol +method+ for
61
+ # +uri+ to be handled according to +options+. If no +method+ is specified, or
62
+ # you explicitly specify <tt>:any</tt>, the response will be reigstered for
63
+ # any request for +uri+. +uri+ can be a +String+ or a +URI+ object. +options+
64
+ # must be either a +Hash+ or an +Array+ of +Hashes+ (see below) that must
65
+ # contain any one of the following keys:
66
+ #
67
+ # <tt>:string</tt>::
68
+ # Takes a +String+ argument that is returned as the body of the response.
69
+ # FakeWeb.register_uri(:get, 'http://example.com/', :string => "Hello World!")
70
+ # <tt>:file</tt>::
71
+ # Takes a valid filesystem path to a file that is slurped and returned as
72
+ # the body of the response.
73
+ # FakeWeb.register_uri(:post, 'http://example.com/', :file => "/tmp/my_response_body.txt")
74
+ # <tt>:response</tt>::
75
+ # Either an <tt>Net::HTTPResponse</tt>, an +IO+ or a +String+.
76
+ #
77
+ # The easier way by far is to pass the <tt>:response</tt> option to
78
+ # +register_uri+ as a +String+ or an (open for reads) +IO+ object which
79
+ # will be used as the complete HTTP response, including headers and body.
80
+ # If the string points to a readable file, this file will be used as the
81
+ # content for the request.
82
+ #
83
+ # To obtain a complete response document, you can use the +curl+ command,
84
+ # like so:
85
+ #
86
+ # curl -i http://www.example.com/ > response_for_www.example.com
87
+ #
88
+ # which can then be used in your test environment like so:
89
+ #
90
+ # FakeWeb.register_uri(:get, 'http://www.example.com/', :response => 'response_for_www.example.com')
91
+ #
92
+ # See the <tt>Net::HTTPResponse</tt>
93
+ # documentation[http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/classes/Net/HTTPResponse.html]
94
+ # for more information on creating custom response objects.
95
+ #
96
+ # +options+ may also be an +Array+ containing a list of the above-described +Hash+.
97
+ # In this case, FakeWeb will rotate through each provided response, you may optionally
98
+ # provide:
99
+ #
100
+ # <tt>:times</tt>::
101
+ # The number of times this response will be used. Decremented by one each time it's called.
102
+ # FakeWeb will use the final provided request indefinitely, regardless of its :times parameter.
103
+ #
104
+ # Two optional arguments are also accepted:
105
+ #
106
+ # <tt>:status</tt>::
107
+ # Passing <tt>:status</tt> as a two-value array will set the response code
108
+ # and message. The defaults are <tt>200</tt> and <tt>OK</tt>, respectively.
109
+ # Example:
110
+ # FakeWeb.register_uri('http://www.example.com/', :response => "Go away!", :status => [ 404, "Not Found" ])
111
+ # <tt>:exception</tt>::
112
+ # The argument passed via <tt>:exception</tt> will be raised when the
113
+ # specified URL is requested. Any +Exception+ class is valid. Example:
114
+ # FakeWeb.register_uri('http://www.example.com/', :exception => Net::HTTPError)
115
+ #
116
+ def self.register_uri(*args)
117
+ method = :any
118
+ case args.length
119
+ when 3 then method, uri, options = *args
120
+ when 2 then uri, options = *args
121
+ else raise ArgumentError.new("wrong number of arguments (#{args.length} for method = :any, uri, options)")
122
+ end
123
+ Registry.instance.register_uri(method, uri, options)
124
+ end
125
+
126
+ # call-seq:
127
+ # FakeWeb.response_for(method, uri, client_library)
128
+ # FakeWeb.response_for(uri, client_library)
129
+ #
130
+ # When using Net::HTTP
131
+ # Returns the faked Net::HTTPResponse object associated with +uri+.
132
+ # When using HTTPClient
133
+ # Returns the faked HTTP::Message object associated with +uri+.
134
+ def self.response_for(*args, &block) #:nodoc: :yields: response
135
+ method = :any
136
+ case args.length
137
+ when 3 then method, client_library, uri = *args
138
+ when 2 then client_library, uri = *args
139
+ else raise ArgumentError.new("wrong number of arguments (#{args.length} for method = :any, uri)")
140
+ end
141
+ Registry.instance.response_for(method, uri, client_library, &block)
142
+ end
143
+
144
+ # call-seq:
145
+ # FakeWeb.registered_uri?(method, uri)
146
+ # FakeWeb.registered_uri?(uri)
147
+ #
148
+ # Returns true if +uri+ is registered with FakeWeb. You can optionally
149
+ # specify +method+ to limit the search to a certain HTTP method (or use
150
+ # <tt>:any</tt> to explicitly check against any method).
151
+ def self.registered_uri?(*args)
152
+ method = :any
153
+ case args.length
154
+ when 2 then method, uri = *args
155
+ when 1 then uri = *args
156
+ else raise ArgumentError.new("wrong number of arguments (#{args.length} for method = :any, uri)")
157
+ end
158
+ Registry.instance.registered_uri?(method, uri)
159
+ end
160
+
161
+ class Registry #:nodoc:
162
+ include Singleton
163
+
164
+ attr_accessor :uri_map
165
+
166
+ def initialize
167
+ clean_registry
168
+ end
169
+
170
+ def clean_registry
171
+ self.uri_map = Hash.new { |hash, key| hash[key] = Hash.new(&hash.default_proc) }
172
+ end
173
+
174
+ def register_uri(method, uri, options)
175
+ uri_map[normalize_uri(uri)][method] = [*[options]].flatten.collect { |option|
176
+ FakeWeb::Responder.new(method, uri, option, option[:times])
177
+ }
178
+ end
179
+
180
+ def registered_uri?(method, uri)
181
+ normalized_uri = normalize_uri(uri)
182
+ uri_map[normalized_uri].has_key?(method) || uri_map[normalized_uri].has_key?(:any)
183
+ end
184
+
185
+ def registered_uri(method, uri)
186
+ uri = normalize_uri(uri)
187
+ registered = registered_uri?(method, uri)
188
+ if registered && uri_map[uri].has_key?(method)
189
+ uri_map[uri][method]
190
+ elsif registered
191
+ uri_map[uri][:any]
192
+ else
193
+ nil
194
+ end
195
+ end
196
+
197
+ def response_for(method, uri, client_library, &block)
198
+ responses = registered_uri(method, uri)
199
+ return nil if responses.nil?
200
+
201
+ next_response = responses.last
202
+ responses.each { |response|
203
+ if response.times and response.times > 0
204
+ response.times -= 1
205
+ next_response = response
206
+ break
207
+ end
208
+ }
209
+
210
+ return next_response.response(client_library, &block)
211
+ end
212
+
213
+ private
214
+
215
+ def normalize_uri(uri)
216
+ case uri
217
+ when URI then uri
218
+ else
219
+ uri = 'http://' + uri unless uri.match('^https?://')
220
+ parsed_uri = URI.parse(uri)
221
+ parsed_uri.query = sort_query_params(parsed_uri.query)
222
+ parsed_uri
223
+ end
224
+ end
225
+
226
+ def sort_query_params(query)
227
+ return nil if query.nil? or query.empty?
228
+ query.split('&').sort.join('&')
229
+ end
230
+ end
231
+
232
+ module Response #:nodoc:
233
+ def read_body(*args, &block)
234
+ yield @body if block_given?
235
+ @body
236
+ end
237
+ end
238
+
239
+ class Responder #:nodoc:
240
+
241
+ attr_accessor :method, :uri, :options, :times
242
+
243
+ def initialize(method, uri, options, times)
244
+ self.method = method
245
+ self.uri = uri
246
+ self.options = options
247
+ self.times = times ? times : 1
248
+ end
249
+
250
+ def response(client_library, &block)
251
+ if has_baked_response?
252
+ response = baked_response
253
+ else
254
+ case client_library
255
+ when :net_http
256
+ code, msg = meta_information
257
+ response = Net::HTTPResponse.send(:response_class, code.to_s).new(uri, code.to_s, msg)
258
+ response.instance_variable_set(:@body, content)
259
+ when :httpclient
260
+ response = HTTP::Message.new_response(content)
261
+ end
262
+ end
263
+ case client_library
264
+ when :net_http
265
+ response.instance_variable_set(:@read, true)
266
+ response.extend FakeWeb::Response
267
+ end
268
+
269
+ optionally_raise(response)
270
+
271
+ yield response if block_given?
272
+
273
+ response
274
+ end
275
+
276
+ private
277
+
278
+ def content
279
+ [ :file, :string ].each do |map_option|
280
+ next unless options.has_key?(map_option)
281
+ return self.send("#{map_option}_response", options[map_option])
282
+ end
283
+
284
+ return ''
285
+ end
286
+
287
+ def file_response(path)
288
+ IO.readlines(path).join("\n")
289
+ end
290
+
291
+ def string_response(string)
292
+ string
293
+ end
294
+
295
+ def baked_response
296
+ resp = case options[:response]
297
+ when Net::HTTPResponse then options[:response]
298
+ when String
299
+ socket = Net::BufferedIO.new(options[:response])
300
+ r = Net::HTTPResponse.read_new(socket)
301
+ r.instance_eval { @header['transfer-encoding'] = nil }
302
+ r.reading_body(socket, true) {}
303
+ r
304
+ else raise StandardError, "Handler unimplemented for response #{options[:response]}"
305
+ end
306
+ end
307
+
308
+ def has_baked_response?
309
+ options.has_key?(:response)
310
+ end
311
+
312
+ def optionally_raise(response)
313
+ return unless options.has_key?(:exception)
314
+ ex_alloc = options[:exception].allocate
315
+ ex_instance = case ex_alloc
316
+ when Net::HTTPError, OpenURI::HTTPError
317
+ options[:exception].new('Exception from FakeWeb', response)
318
+ else options[:exception].new
319
+ end
320
+ raise ex_instance
321
+ end
322
+
323
+ def meta_information
324
+ if options.has_key?(:status); options[:status]
325
+ else; [ 200, 'OK' ]
326
+ end
327
+ end
328
+ end
329
+
330
+ class SocketDelegator #:nodoc:
331
+
332
+ def initialize(delegate=nil)
333
+ @delegate = nil
334
+ end
335
+
336
+ def method_missing(method, *args, &block)
337
+ return @delegate.send(method, *args, &block) if @delegate
338
+ return self.send("my_#{method}", *args, &block)
339
+ end
340
+
341
+ def my_closed?
342
+ @closed ||= true
343
+ end
344
+
345
+ def my_readuntil(*args)
346
+ end
347
+ end
348
+ end