mbleigh-fakeweb 1.1.3.8

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.
data/Rakefile ADDED
@@ -0,0 +1,63 @@
1
+ require 'rubygems'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ task :default => :test
6
+
7
+ desc "Run All Tests"
8
+ Rake::TestTask.new :test do |test|
9
+ test.test_files = ["test/**/*.rb"]
10
+ test.verbose = true
11
+ end
12
+
13
+ desc "Generate Documentation"
14
+ Rake::RDocTask.new do |rdoc|
15
+ rdoc.main = "README.rdoc"
16
+ rdoc.rdoc_dir = "doc"
17
+ rdoc.rdoc_files.include("README.rdoc", "CHANGELOG", "LICENSE.txt", "lib/*.rb")
18
+ rdoc.title = "FakeWeb API Documentation"
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.options << '--charset' << 'utf-8'
21
+ end
22
+
23
+ desc %{Update ".manifest" with the latest list of project filenames. Respect\
24
+ .gitignore by excluding everything that git ignores. Update `files` and\
25
+ `test_files` arrays in "*.gemspec" file if it's present.}
26
+ task :manifest do
27
+ list = Dir['**/*'].sort
28
+ spec_file = Dir['*.gemspec'].first
29
+ list -= [spec_file] if spec_file
30
+
31
+ File.read('.gitignore').each_line do |glob|
32
+ glob = glob.chomp.sub(/^\//, '')
33
+ list -= Dir[glob]
34
+ list -= Dir["#{glob}/**/*"] if File.directory?(glob) and !File.symlink?(glob)
35
+ puts "excluding #{glob}"
36
+ end
37
+
38
+ if spec_file
39
+ spec = File.read spec_file
40
+ spec.gsub! /^(\s* s.(test_)?files \s* = \s* )( \[ [^\]]* \] | %w\( [^)]* \) )/mx do
41
+ assignment = $1
42
+ bunch = $2 ? list.grep(/^test\//) : list
43
+ '%s%%w(%s)' % [assignment, bunch.join(' ')]
44
+ end
45
+
46
+ File.open(spec_file, 'w') {|f| f << spec }
47
+ end
48
+ File.open('.manifest', 'w') {|f| f << list.join("\n") }
49
+ end
50
+
51
+ if RUBY_PLATFORM =~ /java/
52
+ puts "rcov support disabled (running under JRuby)."
53
+ elsif RUBY_VERSION =~ /^1\.9/
54
+ puts "rcov support disabled (running under Ruby 1.9)"
55
+ else
56
+ require 'rcov/rcovtask'
57
+ Rcov::RcovTask.new do |t|
58
+ t.test_files = FileList['test/**/test*.rb']
59
+ t.rcov_opts << "--sort coverage"
60
+ t.rcov_opts << "--exclude gems"
61
+ t.rcov_opts << "--no-validator-links"
62
+ end
63
+ end
data/lib/fake_web.rb ADDED
@@ -0,0 +1,153 @@
1
+ require 'singleton'
2
+
3
+ require 'fake_web/ext/net_http'
4
+ require 'fake_web/registry'
5
+ require 'fake_web/response'
6
+ require 'fake_web/responder'
7
+ require 'fake_web/stub_socket'
8
+
9
+ module FakeWeb
10
+
11
+ # Resets the FakeWeb Registry. This will force all subsequent web requests to
12
+ # behave as real requests.
13
+ def self.clean_registry
14
+ Registry.instance.clean_registry
15
+ end
16
+
17
+ # Enables or disables real HTTP connections for requests that don't match
18
+ # registered URIs.
19
+ #
20
+ # If you set <tt>FakeWeb.allow_net_connect = false</tt> and subsequently try
21
+ # to make a request to a URI you haven't registered with #register_uri, a
22
+ # NetConnectNotAllowedError will be raised. This is handy when you want to
23
+ # make sure your tests are self-contained, or want to catch the scenario
24
+ # when a URI is changed in implementation code without a corresponding test
25
+ # change.
26
+ #
27
+ # When <tt>FakeWeb.allow_net_connect = true</tt> (the default), requests to
28
+ # URIs not stubbed with FakeWeb are passed through to Net::HTTP.
29
+ def self.allow_net_connect=(allowed)
30
+ @allow_net_connect = allowed
31
+ end
32
+
33
+ # Enable pass-through to Net::HTTP by default.
34
+ self.allow_net_connect = true
35
+
36
+ # Returns +true+ if requests to URIs not registered with FakeWeb are passed
37
+ # through to Net::HTTP for normal processing (the default). Returns +false+
38
+ # if an exception is raised for these requests.
39
+ def self.allow_net_connect?
40
+ @allow_net_connect
41
+ end
42
+
43
+ # This exception is raised if you set <tt>FakeWeb.allow_net_connect =
44
+ # false</tt> and subsequently try to make a request to a URI you haven't
45
+ # stubbed.
46
+ class NetConnectNotAllowedError < StandardError; end;
47
+
48
+ # call-seq:
49
+ # FakeWeb.register_uri(method, uri, options)
50
+ # FakeWeb.register_uri(uri, options)
51
+ #
52
+ # Register requests using the HTTP method specified by the symbol +method+ for
53
+ # +uri+ to be handled according to +options+. If no +method+ is specified, or
54
+ # you explicitly specify <tt>:any</tt>, the response will be reigstered for
55
+ # any request for +uri+. +uri+ can be a +String+ or a +URI+ object. +options+
56
+ # must be either a +Hash+ or an +Array+ of +Hashes+ (see below) that must
57
+ # contain any one of the following keys:
58
+ #
59
+ # <tt>:string</tt>::
60
+ # Takes a +String+ argument that is returned as the body of the response.
61
+ # FakeWeb.register_uri(:get, 'http://example.com/', :string => "Hello World!")
62
+ # <tt>:file</tt>::
63
+ # Takes a valid filesystem path to a file that is slurped and returned as
64
+ # the body of the response.
65
+ # FakeWeb.register_uri(:post, 'http://example.com/', :file => "/tmp/my_response_body.txt")
66
+ # <tt>:response</tt>::
67
+ # Either an <tt>Net::HTTPResponse</tt>, an +IO+ or a +String+.
68
+ #
69
+ # The easier way by far is to pass the <tt>:response</tt> option to
70
+ # +register_uri+ as a +String+ or an (open for reads) +IO+ object which
71
+ # will be used as the complete HTTP response, including headers and body.
72
+ # If the string points to a readable file, this file will be used as the
73
+ # content for the request.
74
+ #
75
+ # To obtain a complete response document, you can use the +curl+ command,
76
+ # like so:
77
+ #
78
+ # curl -i http://www.example.com/ > response_for_www.example.com
79
+ #
80
+ # which can then be used in your test environment like so:
81
+ #
82
+ # FakeWeb.register_uri(:get, 'http://www.example.com/', :response => 'response_for_www.example.com')
83
+ #
84
+ # See the <tt>Net::HTTPResponse</tt>
85
+ # documentation[http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/classes/Net/HTTPResponse.html]
86
+ # for more information on creating custom response objects.
87
+ #
88
+ # +options+ may also be an +Array+ containing a list of the above-described +Hash+.
89
+ # In this case, FakeWeb will rotate through each provided response, you may optionally
90
+ # provide:
91
+ #
92
+ # <tt>:times</tt>::
93
+ # The number of times this response will be used. Decremented by one each time it's called.
94
+ # FakeWeb will use the final provided request indefinitely, regardless of its :times parameter.
95
+ #
96
+ # Two optional arguments are also accepted:
97
+ #
98
+ # <tt>:status</tt>::
99
+ # Passing <tt>:status</tt> as a two-value array will set the response code
100
+ # and message. The defaults are <tt>200</tt> and <tt>OK</tt>, respectively.
101
+ # Example:
102
+ # FakeWeb.register_uri('http://www.example.com/', :response => "Go away!", :status => [ 404, "Not Found" ])
103
+ # <tt>:exception</tt>::
104
+ # The argument passed via <tt>:exception</tt> will be raised when the
105
+ # specified URL is requested. Any +Exception+ class is valid. Example:
106
+ # FakeWeb.register_uri('http://www.example.com/', :exception => Net::HTTPError)
107
+ #
108
+ def self.register_uri(*args)
109
+ method = :any
110
+ case args.length
111
+ when 3 then method, uri, options = *args
112
+ when 2 then uri, options = *args
113
+ else raise ArgumentError.new("wrong number of arguments (#{args.length} for method = :any, uri, options)")
114
+ end
115
+
116
+ Registry.instance.register_uri(method, uri, options)
117
+ end
118
+
119
+ # call-seq:
120
+ # FakeWeb.response_for(method, uri)
121
+ # FakeWeb.response_for(uri)
122
+ #
123
+ # Returns the faked Net::HTTPResponse object associated with +uri+.
124
+ def self.response_for(*args, &block) #:nodoc: :yields: response
125
+ method = :any
126
+ case args.length
127
+ when 2 then method, uri = args
128
+ when 1 then uri = args.first
129
+ else raise ArgumentError.new("wrong number of arguments (#{args.length} for method = :any, uri)")
130
+ end
131
+
132
+ Registry.instance.response_for(method, uri, &block)
133
+ end
134
+
135
+ # call-seq:
136
+ # FakeWeb.registered_uri?(method, uri)
137
+ # FakeWeb.registered_uri?(uri)
138
+ #
139
+ # Returns true if +uri+ is registered with FakeWeb. You can optionally
140
+ # specify +method+ to limit the search to a certain HTTP method (or use
141
+ # <tt>:any</tt> to explicitly check against any method).
142
+ def self.registered_uri?(*args)
143
+ method = :any
144
+ case args.length
145
+ when 2 then method, uri = args
146
+ when 1 then uri = args.first
147
+ else raise ArgumentError.new("wrong number of arguments (#{args.length} for method = :any, uri)")
148
+ end
149
+
150
+ Registry.instance.registered_uri?(method, uri)
151
+ end
152
+
153
+ end
@@ -0,0 +1,59 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'stringio'
4
+ require 'base64'
5
+
6
+ module Net #:nodoc: all
7
+
8
+ class BufferedIO
9
+ def initialize(io, debug_output = nil)
10
+ @read_timeout = 60
11
+ @rbuf = ''
12
+ @debug_output = debug_output
13
+
14
+ @io = case io
15
+ when Socket, OpenSSL::SSL::SSLSocket, IO
16
+ io
17
+ when String
18
+ File.exists?(io) ? File.open(io, "r") : StringIO.new(io)
19
+ end
20
+ raise "Unable to create local socket" unless @io
21
+ end
22
+ end
23
+
24
+ class HTTP
25
+ def self.socket_type
26
+ FakeWeb::StubSocket
27
+ end
28
+
29
+ alias :original_net_http_request :request
30
+ alias :original_net_http_connect :connect
31
+
32
+ def request(request, body = nil, &block)
33
+ protocol = use_ssl? ? "https" : "http"
34
+
35
+ path = request.path
36
+ path = URI.parse(request.path).request_uri if request.path =~ /^http/
37
+
38
+ userinfo = Base64.decode64(request['authorization'].split.last) rescue nil
39
+
40
+ uri = "#{protocol}://#{"#{userinfo}@" if userinfo}#{self.address}:#{self.port}#{path}"
41
+ method = request.method.downcase.to_sym
42
+
43
+ if FakeWeb.registered_uri?(method, uri)
44
+ @socket = Net::HTTP.socket_type.new
45
+ FakeWeb.response_for(method, uri, &block)
46
+ elsif FakeWeb.allow_net_connect?
47
+ original_net_http_connect
48
+ original_net_http_request(request, body, &block)
49
+ else
50
+ raise FakeWeb::NetConnectNotAllowedError,
51
+ "Real HTTP connections are disabled. Unregistered request: #{request.method} #{uri}"
52
+ end
53
+ end
54
+
55
+ def connect
56
+ end
57
+ end
58
+
59
+ end
@@ -0,0 +1,78 @@
1
+ module FakeWeb
2
+ class Registry #:nodoc:
3
+ include Singleton
4
+
5
+ attr_accessor :uri_map
6
+
7
+ def initialize
8
+ clean_registry
9
+ end
10
+
11
+ def clean_registry
12
+ self.uri_map = Hash.new do |hash, key|
13
+ hash[key] = Hash.new(&hash.default_proc)
14
+ end
15
+ end
16
+
17
+ def register_uri(method, uri, options)
18
+ uri_map[normalize_uri(uri)][method] = [*[options]].flatten.collect do |option|
19
+ FakeWeb::Responder.new(method, uri, option, option[:times])
20
+ end
21
+ end
22
+
23
+ def registered_uri?(method, uri)
24
+ normalized_uri = normalize_uri(uri)
25
+ uri_map[normalized_uri].has_key?(method) || uri_map[normalized_uri].has_key?(:any)
26
+ end
27
+
28
+ def registered_uri(method, uri)
29
+ uri = normalize_uri(uri)
30
+ registered = registered_uri?(method, uri)
31
+ if registered && uri_map[uri].has_key?(method)
32
+ uri_map[uri][method]
33
+ elsif registered
34
+ uri_map[uri][:any]
35
+ else
36
+ nil
37
+ end
38
+ end
39
+
40
+ def response_for(method, uri, &block)
41
+ responses = registered_uri(method, uri)
42
+ return nil if responses.nil?
43
+
44
+ next_response = responses.last
45
+ responses.each do |response|
46
+ if response.times and response.times > 0
47
+ response.times -= 1
48
+ next_response = response
49
+ break
50
+ end
51
+ end
52
+
53
+ next_response.response(&block)
54
+ end
55
+
56
+ private
57
+
58
+ def normalize_uri(uri)
59
+ case uri
60
+ when URI then uri
61
+ else
62
+ uri = 'http://' + uri unless uri.match('^https?://')
63
+ parsed_uri = URI.parse(uri)
64
+ parsed_uri.query = sort_query_params(parsed_uri.query)
65
+ parsed_uri
66
+ end
67
+ end
68
+
69
+ def sort_query_params(query)
70
+ if query.nil? || query.empty?
71
+ nil
72
+ else
73
+ query.split('&').sort.join('&')
74
+ end
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,99 @@
1
+ module FakeWeb
2
+ class Responder #:nodoc:
3
+
4
+ attr_accessor :method, :uri, :options, :times
5
+
6
+ def initialize(method, uri, options, times)
7
+ self.method = method
8
+ self.uri = uri
9
+ self.options = options
10
+ self.times = times ? times : 1
11
+ end
12
+
13
+ def response(&block)
14
+ if has_baked_response?
15
+ response = baked_response
16
+ else
17
+ code, msg = meta_information
18
+ response = Net::HTTPResponse.send(:response_class, code.to_s).new(uri, code.to_s, msg)
19
+ response.instance_variable_set(:@body, content)
20
+ end
21
+
22
+ response.instance_variable_set(:@read, true)
23
+ response.extend FakeWeb::Response
24
+
25
+ optionally_raise(response)
26
+
27
+ yield response if block_given?
28
+
29
+ response
30
+ end
31
+
32
+ private
33
+
34
+ def content
35
+ [ :file, :string ].each do |map_option|
36
+ next unless options.has_key?(map_option)
37
+ return self.send("#{map_option}_response", options[map_option])
38
+ end
39
+
40
+ return ''
41
+ end
42
+
43
+ def file_response(path)
44
+ IO.read(path)
45
+ end
46
+
47
+ def string_response(string)
48
+ string
49
+ end
50
+
51
+ def baked_response
52
+ resp = case options[:response]
53
+ when Net::HTTPResponse then options[:response]
54
+ when String
55
+ socket = Net::BufferedIO.new(options[:response])
56
+ r = Net::HTTPResponse.read_new(socket)
57
+
58
+ # Store the oiriginal transfer-encoding
59
+ saved_transfer_encoding = r.instance_eval {
60
+ @header['transfer-encoding'] if @header.key?('transfer-encoding')
61
+ }
62
+
63
+ # read the body of response.
64
+ r.instance_eval { @header['transfer-encoding'] = nil }
65
+ r.reading_body(socket, true) {}
66
+
67
+ # Delete the transfer-encoding key from r.@header if there wasn't one,
68
+ # else restore the saved_transfer_encoding.
69
+ if saved_transfer_encoding.nil?
70
+ r.instance_eval { @header.delete('transfer-encoding') }
71
+ else
72
+ r.instance_eval { @header['transfer-encoding'] = saved_transfer_encoding }
73
+ end
74
+ r
75
+ else raise StandardError, "Handler unimplemented for response #{options[:response]}"
76
+ end
77
+ end
78
+
79
+ def has_baked_response?
80
+ options.has_key?(:response)
81
+ end
82
+
83
+ def optionally_raise(response)
84
+ return unless options.has_key?(:exception)
85
+ ex_alloc = options[:exception].allocate
86
+ ex_instance = case ex_alloc
87
+ when Net::HTTPError, OpenURI::HTTPError
88
+ options[:exception].new('Exception from FakeWeb', response)
89
+ else options[:exception].new
90
+ end
91
+ raise ex_instance
92
+ end
93
+
94
+ def meta_information
95
+ options.has_key?(:status) ? options[:status] : [200, 'OK']
96
+ end
97
+
98
+ end
99
+ end