webmock 1.0.0 → 1.1.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 (35) hide show
  1. data/CHANGELOG.md +17 -0
  2. data/README.md +13 -0
  3. data/VERSION +1 -1
  4. data/lib/webmock/errors.rb +5 -1
  5. data/lib/webmock/http_lib_adapters/httpclient.rb +10 -8
  6. data/lib/webmock/http_lib_adapters/net_http.rb +56 -64
  7. data/lib/webmock/http_lib_adapters/patron.rb +2 -3
  8. data/lib/webmock/util/headers.rb +18 -3
  9. data/lib/webmock/webmock.rb +12 -5
  10. data/spec/example_curl_output.txt +2 -0
  11. data/spec/httpclient_spec.rb +8 -0
  12. data/spec/httpclient_spec_helper.rb +9 -1
  13. data/spec/net_http_spec_helper.rb +10 -1
  14. data/spec/other_net_http_libs_spec.rb +0 -10
  15. data/spec/patron_spec_helper.rb +8 -2
  16. data/spec/response_spec.rb +4 -2
  17. data/spec/util/headers_spec.rb +17 -0
  18. data/spec/webmock_spec.rb +103 -15
  19. data/test/test_webmock.rb +1 -1
  20. data/webmock.gemspec +2 -23
  21. metadata +2 -23
  22. data/spec/vendor/samuel-0.2.1/.document +0 -5
  23. data/spec/vendor/samuel-0.2.1/.gitignore +0 -5
  24. data/spec/vendor/samuel-0.2.1/LICENSE +0 -20
  25. data/spec/vendor/samuel-0.2.1/README.rdoc +0 -70
  26. data/spec/vendor/samuel-0.2.1/Rakefile +0 -62
  27. data/spec/vendor/samuel-0.2.1/VERSION +0 -1
  28. data/spec/vendor/samuel-0.2.1/lib/samuel.rb +0 -52
  29. data/spec/vendor/samuel-0.2.1/lib/samuel/net_http.rb +0 -10
  30. data/spec/vendor/samuel-0.2.1/lib/samuel/request.rb +0 -96
  31. data/spec/vendor/samuel-0.2.1/samuel.gemspec +0 -69
  32. data/spec/vendor/samuel-0.2.1/test/request_test.rb +0 -193
  33. data/spec/vendor/samuel-0.2.1/test/samuel_test.rb +0 -42
  34. data/spec/vendor/samuel-0.2.1/test/test_helper.rb +0 -66
  35. data/spec/vendor/samuel-0.2.1/test/thread_test.rb +0 -32
@@ -1,70 +0,0 @@
1
- = Samuel
2
-
3
- Samuel is a gem for automatic logging of your Net::HTTP requests. It's named for
4
- the serial diarist Mr. Pepys, who was known to reliably record events both
5
- quotidian and remarkable.
6
-
7
- Should a Great Plague, Fire, or Whale befall an important external web service
8
- you use, you'll be sure to have a tidy record of it.
9
-
10
- == Usage:
11
-
12
- When Rails is loaded, Samuel configures a few things automatically. So all you
13
- need to do is this:
14
-
15
- # config/environment.rb
16
- config.gem "samuel"
17
-
18
- And Samuel will automatically use Rails's logger and an ActiveRecord-like format.
19
-
20
- For non-Rails projects, you'll have to manually configure logging, like this:
21
-
22
- require 'samuel'
23
- Samuel.logger = Logger.new('http_requests.log')
24
-
25
- If you don't assign a logger, Samuel will configure a default logger on +STDOUT+.
26
-
27
- == Configuration
28
-
29
- There are two ways to specify configuration options for Samuel: global and
30
- inline. Global configs look like this:
31
-
32
- Samuel.config[:labels] = {"example.com" => "Example API"}
33
- Samuel.config[:filtered_params] = :password
34
-
35
- You should put global configuration somewhere early-on in your program. If
36
- you're using Rails, <tt>config/initializers/samuel.rb</tt> will do the trick.
37
-
38
- Alternatively, an inline configuration block temporarily overrides any global
39
- configuration for a set of HTTP requests:
40
-
41
- Samuel.with_config :label => "Twitter API" do
42
- Net::HTTP.start("twitter.com") { |http| http.get("/help/test") }
43
- end
44
-
45
- Right now, there are three configuration changes you can make in either style:
46
-
47
- * +:labels+ - This is a hash with domain substrings as keys and log labels as
48
- values. If a request domain includes one of the domain substrings, the
49
- corresponding label will be used for the first part of that log entry. By
50
- default this is set to <tt>\{"" => "HTTP"}</tt>, so that all requests are
51
- labeled with <tt>"HTTP Request"</tt>.
52
- * +:label+ - As an alternative to the +:labels+ hash, this is simply a string.
53
- If set, it takes precedence over any +:labels+ (by default, it's not set). It
54
- gets <tt>"Request"</tt> appended to it as well -- so if you want your log to
55
- always say +Twitter API Request+ instead of the default +HTTP Request+, you
56
- can set this to <tt>"Twitter API"</tt>. I'd recommend using this setting
57
- globally if you're only making requests to one service, or inline if you just
58
- need to temporarily override the global +:labels+.
59
- * +:filtered_params+ - This works just like Rails's +filter_parameter_logging+
60
- method. Set it to a symbol, string, or array of them, and Samuel will filter
61
- the value of query parameters that have any of these patterns as a substring
62
- by replacing the value with <tt>[FILTERED]</tt> in your logs. By default, no
63
- filtering is enabled.
64
-
65
- Samuel logs successful HTTP requests at the +INFO+ level; Failed requests log at
66
- the +WARN+ level. This isn't currently configurable, but it's on the list.
67
-
68
- == License
69
-
70
- Copyright 2009 Chris Kampmeier. See +LICENSE+ for details.
@@ -1,62 +0,0 @@
1
- require 'rubygems'
2
- require 'rake'
3
-
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "samuel"
8
- gem.summary = %Q{An automatic logger for HTTP requests in Ruby}
9
- gem.description = %Q{An automatic logger for HTTP requests in Ruby. Adds Net::HTTP request logging to your Rails logs, and more.}
10
- gem.email = "chris@kampers.net"
11
- gem.homepage = "http://github.com/chrisk/samuel"
12
- gem.authors = ["Chris Kampmeier"]
13
- gem.rubyforge_project = "samuel"
14
- gem.add_development_dependency "thoughtbot-shoulda"
15
- gem.add_development_dependency "yard"
16
- gem.add_development_dependency "mocha"
17
- gem.add_development_dependency "fakeweb"
18
- end
19
- Jeweler::GemcutterTasks.new
20
- Jeweler::RubyforgeTasks.new do |rubyforge|
21
- rubyforge.doc_task = "yardoc"
22
- end
23
- rescue LoadError
24
- puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
25
- end
26
-
27
- require 'rake/testtask'
28
- Rake::TestTask.new(:test) do |test|
29
- test.libs << 'lib' << 'test'
30
- test.pattern = 'test/**/*_test.rb'
31
- test.verbose = false
32
- test.warning = true
33
- end
34
-
35
- begin
36
- require 'rcov/rcovtask'
37
- Rcov::RcovTask.new do |test|
38
- test.libs << 'test'
39
- test.pattern = 'test/**/*_test.rb'
40
- test.rcov_opts << "--sort coverage"
41
- test.rcov_opts << "--exclude gems"
42
- test.verbose = false
43
- test.warning = true
44
- end
45
- rescue LoadError
46
- task :rcov do
47
- abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
48
- end
49
- end
50
-
51
- task :test => :check_dependencies
52
-
53
- task :default => :test
54
-
55
- begin
56
- require 'yard'
57
- YARD::Rake::YardocTask.new
58
- rescue LoadError
59
- task :yardoc do
60
- abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
61
- end
62
- end
@@ -1 +0,0 @@
1
- 0.2.1
@@ -1,52 +0,0 @@
1
- require "logger"
2
- require "net/http"
3
- require "net/https"
4
- require "benchmark"
5
-
6
- require "samuel/net_http"
7
- require "samuel/request"
8
-
9
-
10
- module Samuel
11
- extend self
12
-
13
- attr_writer :config, :logger
14
-
15
- def logger
16
- @logger = nil if !defined?(@logger)
17
- return @logger if !@logger.nil?
18
-
19
- if defined?(RAILS_DEFAULT_LOGGER)
20
- @logger = RAILS_DEFAULT_LOGGER
21
- else
22
- @logger = Logger.new(STDOUT)
23
- end
24
- end
25
-
26
- def config
27
- Thread.current[:__samuel_config] ? Thread.current[:__samuel_config] : @config
28
- end
29
-
30
- def log_request(http, request, &block)
31
- request = Request.new(http, request, block)
32
- request.perform_and_log!
33
- request.response
34
- end
35
-
36
- def with_config(options = {})
37
- original_config = config.dup
38
- nested = !Thread.current[:__samuel_config].nil?
39
-
40
- Thread.current[:__samuel_config] = original_config.merge(options)
41
- yield
42
- Thread.current[:__samuel_config] = nested ? original_config : nil
43
- end
44
-
45
- def reset_config
46
- Thread.current[:__samuel_config] = nil
47
- @config = {:label => nil, :labels => {"" => "HTTP"}, :filtered_params => []}
48
- end
49
-
50
- end
51
-
52
- Samuel.reset_config
@@ -1,10 +0,0 @@
1
- class Net::HTTP
2
-
3
- alias request_without_samuel request
4
- def request(req, body = nil, &block)
5
- Samuel.log_request(self, req) do
6
- request_without_samuel(req, body, &block)
7
- end
8
- end
9
-
10
- end
@@ -1,96 +0,0 @@
1
- module Samuel
2
- class Request
3
-
4
- attr_accessor :response
5
-
6
- def initialize(http, request, proc)
7
- @http, @request, @proc = http, request, proc
8
- end
9
-
10
- def perform_and_log!
11
- # If an exception is raised in the Benchmark block, it'll interrupt the
12
- # benchmark. Instead, use an inner block to record it as the "response"
13
- # for raising after the benchmark (and logging) is done.
14
- @seconds = Benchmark.realtime do
15
- begin; @response = @proc.call; rescue Exception => @response; end
16
- end
17
- Samuel.logger.add(log_level, log_message)
18
- raise @response if @response.is_a?(Exception)
19
- end
20
-
21
- private
22
-
23
- def log_message
24
- bold = "\e[1m"
25
- blue = "\e[34m"
26
- underline = "\e[4m"
27
- reset = "\e[0m"
28
- " #{bold}#{blue}#{underline}#{label} request (#{milliseconds}ms) " +
29
- "#{response_summary}#{reset} #{method} #{uri}"
30
- end
31
-
32
- def milliseconds
33
- (@seconds * 1000).round
34
- end
35
-
36
- def uri
37
- "#{scheme}://#{@http.address}#{port_if_not_default}#{filtered_path}"
38
- end
39
-
40
- def filtered_path
41
- path_without_query, query = @request.path.split("?")
42
- if query
43
- patterns = [Samuel.config[:filtered_params]].flatten
44
- patterns.map { |pattern|
45
- pattern_for_regex = Regexp.escape(pattern.to_s)
46
- [/([^&]*#{pattern_for_regex}[^&=]*)=(?:[^&]+)/, '\1=[FILTERED]']
47
- }.each { |filter| query.gsub!(*filter) }
48
- "#{path_without_query}?#{query}"
49
- else
50
- @request.path
51
- end
52
- end
53
-
54
- def scheme
55
- @http.use_ssl? ? "https" : "http"
56
- end
57
-
58
- def port_if_not_default
59
- ssl, port = @http.use_ssl?, @http.port
60
- if (!ssl && port == 80) || (ssl && port == 443)
61
- ""
62
- else
63
- ":#{port}"
64
- end
65
- end
66
-
67
- def method
68
- @request.method.to_s.upcase
69
- end
70
-
71
- def label
72
- return Samuel.config[:label] if Samuel.config[:label]
73
-
74
- pair = Samuel.config[:labels].detect { |domain, label| @http.address.include?(domain) }
75
- pair[1] if pair
76
- end
77
-
78
- def response_summary
79
- if response.is_a?(Exception)
80
- response.class
81
- else
82
- "[#{response.code} #{response.message}]"
83
- end
84
- end
85
-
86
- def log_level
87
- error_classes = [Exception, Net::HTTPClientError, Net::HTTPServerError]
88
- if error_classes.any? { |klass| response.is_a?(klass) }
89
- level = Logger::WARN
90
- else
91
- level = Logger::INFO
92
- end
93
- end
94
-
95
- end
96
- end
@@ -1,69 +0,0 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
- # -*- encoding: utf-8 -*-
5
-
6
- Gem::Specification.new do |s|
7
- s.name = %q{samuel}
8
- s.version = "0.2.1"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Chris Kampmeier"]
12
- s.date = %q{2009-09-15}
13
- s.description = %q{An automatic logger for HTTP requests in Ruby. Adds Net::HTTP request logging to your Rails logs, and more.}
14
- s.email = %q{chris@kampers.net}
15
- s.extra_rdoc_files = [
16
- "LICENSE",
17
- "README.rdoc"
18
- ]
19
- s.files = [
20
- ".document",
21
- ".gitignore",
22
- "LICENSE",
23
- "README.rdoc",
24
- "Rakefile",
25
- "VERSION",
26
- "lib/samuel.rb",
27
- "lib/samuel/net_http.rb",
28
- "lib/samuel/request.rb",
29
- "samuel.gemspec",
30
- "test/request_test.rb",
31
- "test/samuel_test.rb",
32
- "test/test_helper.rb",
33
- "test/thread_test.rb"
34
- ]
35
- s.homepage = %q{http://github.com/chrisk/samuel}
36
- s.rdoc_options = ["--charset=UTF-8"]
37
- s.require_paths = ["lib"]
38
- s.rubyforge_project = %q{samuel}
39
- s.rubygems_version = %q{1.3.5}
40
- s.summary = %q{An automatic logger for HTTP requests in Ruby}
41
- s.test_files = [
42
- "test/request_test.rb",
43
- "test/samuel_test.rb",
44
- "test/test_helper.rb",
45
- "test/thread_test.rb"
46
- ]
47
-
48
- if s.respond_to? :specification_version then
49
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
50
- s.specification_version = 3
51
-
52
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
53
- s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
54
- s.add_development_dependency(%q<yard>, [">= 0"])
55
- s.add_development_dependency(%q<mocha>, [">= 0"])
56
- s.add_development_dependency(%q<fakeweb>, [">= 0"])
57
- else
58
- s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
59
- s.add_dependency(%q<yard>, [">= 0"])
60
- s.add_dependency(%q<mocha>, [">= 0"])
61
- s.add_dependency(%q<fakeweb>, [">= 0"])
62
- end
63
- else
64
- s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
65
- s.add_dependency(%q<yard>, [">= 0"])
66
- s.add_dependency(%q<mocha>, [">= 0"])
67
- s.add_dependency(%q<fakeweb>, [">= 0"])
68
- end
69
- end
@@ -1,193 +0,0 @@
1
- require 'test_helper'
2
-
3
- class RequestTest < Test::Unit::TestCase
4
-
5
- context "making an HTTP request" do
6
- setup { setup_test_logger
7
- FakeWeb.clean_registry
8
- Samuel.reset_config }
9
- teardown { teardown_test_logger }
10
-
11
- context "to GET http://example.com/test, responding with a 200 in 53ms" do
12
- setup do
13
- FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
14
- Benchmark.stubs(:realtime).yields.returns(0.053)
15
- open "http://example.com/test"
16
- end
17
-
18
- should_log_lines 1
19
- should_log_at_level :info
20
- should_log_including "HTTP request"
21
- should_log_including "(53ms)"
22
- should_log_including "[200 OK]"
23
- should_log_including "GET http://example.com/test"
24
- end
25
-
26
- context "on a non-standard port" do
27
- setup do
28
- FakeWeb.register_uri(:get, "http://example.com:8080/test", :status => [200, "OK"])
29
- open "http://example.com:8080/test"
30
- end
31
-
32
- should_log_including "GET http://example.com:8080/test"
33
- end
34
-
35
- context "with SSL" do
36
- setup do
37
- FakeWeb.register_uri(:get, "https://example.com/test", :status => [200, "OK"])
38
- open "https://example.com/test"
39
- end
40
-
41
- should_log_including "HTTP request"
42
- should_log_including "GET https://example.com/test"
43
- end
44
-
45
- context "with SSL on a non-standard port" do
46
- setup do
47
- FakeWeb.register_uri(:get, "https://example.com:80/test", :status => [200, "OK"])
48
- open "https://example.com:80/test"
49
- end
50
-
51
- should_log_including "HTTP request"
52
- should_log_including "GET https://example.com:80/test"
53
- end
54
-
55
- context "that raises" do
56
- setup do
57
- FakeWeb.register_uri(:get, "http://example.com/test", :exception => Errno::ECONNREFUSED)
58
- begin
59
- Net::HTTP.start("example.com") { |http| http.get("/test") }
60
- rescue Errno::ECONNREFUSED => @exception
61
- end
62
- end
63
-
64
- should_log_at_level :warn
65
- should_log_including "HTTP request"
66
- should_log_including "GET http://example.com/test"
67
- should_log_including "Errno::ECONNREFUSED"
68
- should_log_including %r|\d+ms|
69
- should_raise_exception Errno::ECONNREFUSED
70
- end
71
-
72
- context "that responds with a 500-level code" do
73
- setup do
74
- FakeWeb.register_uri(:get, "http://example.com/test", :status => [502, "Bad Gateway"])
75
- Net::HTTP.start("example.com") { |http| http.get("/test") }
76
- end
77
-
78
- should_log_at_level :warn
79
- end
80
-
81
- context "that responds with a 400-level code" do
82
- setup do
83
- FakeWeb.register_uri(:get, "http://example.com/test", :status => [404, "Not Found"])
84
- Net::HTTP.start("example.com") { |http| http.get("/test") }
85
- end
86
-
87
- should_log_at_level :warn
88
- end
89
-
90
- context "inside a configuration block with :label => 'Example'" do
91
- setup do
92
- FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
93
- Samuel.with_config :label => "Example" do
94
- open "http://example.com/test"
95
- end
96
- end
97
-
98
- should_log_including "Example request"
99
- should_have_config_afterwards_including :labels => {"" => "HTTP"},
100
- :label => nil
101
- end
102
-
103
- context "inside a configuration block with :filter_params" do
104
- setup do
105
- FakeWeb.register_uri(:get, "http://example.com/test?password=secret&username=chrisk",
106
- :status => [200, "OK"])
107
- @uri = "http://example.com/test?password=secret&username=chrisk"
108
- end
109
-
110
- context "=> :password" do
111
- setup { Samuel.with_config(:filtered_params => :password) { open @uri } }
112
- should_log_including "http://example.com/test?password=[FILTERED]&username=chrisk"
113
- end
114
-
115
- context "=> :as" do
116
- setup { Samuel.with_config(:filtered_params => :ass) { open @uri } }
117
- should_log_including "http://example.com/test?password=[FILTERED]&username=chrisk"
118
- end
119
-
120
- context "=> ['pass', 'name']" do
121
- setup { Samuel.with_config(:filtered_params => %w(pass name)) { open @uri } }
122
- should_log_including "http://example.com/test?password=[FILTERED]&username=[FILTERED]"
123
- end
124
- end
125
-
126
- context "with a global config including :label => 'Example'" do
127
- setup do
128
- FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
129
- Samuel.config[:label] = "Example"
130
- open "http://example.com/test"
131
- end
132
-
133
- should_log_including "Example request"
134
- should_have_config_afterwards_including :labels => {"" => "HTTP"},
135
- :label => "Example"
136
- end
137
-
138
- context "with a global config including :label => 'Example' but inside config block that changes it to 'Example 2'" do
139
- setup do
140
- FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
141
- Samuel.config[:label] = "Example"
142
- Samuel.with_config(:label => "Example 2") { open "http://example.com/test" }
143
- end
144
-
145
- should_log_including "Example 2 request"
146
- should_have_config_afterwards_including :labels => {"" => "HTTP"},
147
- :label => "Example"
148
- end
149
-
150
- context "inside a config block of :label => 'Example 2' nested inside a config block of :label => 'Example'" do
151
- setup do
152
- FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
153
- Samuel.with_config :label => "Example" do
154
- Samuel.with_config :label => "Example 2" do
155
- open "http://example.com/test"
156
- end
157
- end
158
- end
159
-
160
- should_log_including "Example 2 request"
161
- should_have_config_afterwards_including :labels => {"" => "HTTP"},
162
- :label => nil
163
- end
164
-
165
- context "wth a global config including :labels => {'example.com' => 'Example'} but inside a config block of :label => 'Example 3' nested inside a config block of :label => 'Example 2'" do
166
- setup do
167
- FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
168
- Samuel.config[:labels] = {'example.com' => 'Example'}
169
- Samuel.with_config :label => "Example 2" do
170
- Samuel.with_config :label => "Example 3" do
171
- open "http://example.com/test"
172
- end
173
- end
174
- end
175
-
176
- should_log_including "Example 3 request"
177
- should_have_config_afterwards_including :labels => {'example.com' => 'Example'},
178
- :label => nil
179
- end
180
-
181
- context "with a global config including :labels => {'example.com' => 'Example API'}" do
182
- setup do
183
- FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
184
- Samuel.config[:labels] = {'example.com' => 'Example API'}
185
- open "http://example.com/test"
186
- end
187
-
188
- should_log_including "Example API request"
189
- end
190
-
191
- end
192
-
193
- end