pax_global_header 0000666 0000000 0000000 00000000064 12152633241 0014511 g ustar 00root root 0000000 0000000 52 comment=90b408999413cff9ff06d59b9d542aeeaa2a5044
ruby-samuel-0.3.3/ 0000775 0000000 0000000 00000000000 12152633241 0013761 5 ustar 00root root 0000000 0000000 ruby-samuel-0.3.3/.document 0000664 0000000 0000000 00000000074 12152633241 0015601 0 ustar 00root root 0000000 0000000 README.rdoc
lib/**/*.rb
bin/*
features/**/*.feature
LICENSE
ruby-samuel-0.3.3/.gitignore 0000664 0000000 0000000 00000000063 12152633241 0015750 0 ustar 00root root 0000000 0000000 .DS_Store
.yardoc
Gemfile.lock
/coverage
/doc
/pkg
ruby-samuel-0.3.3/Gemfile 0000664 0000000 0000000 00000000124 12152633241 0015251 0 ustar 00root root 0000000 0000000 source "http://rubygems.org"
gemspec
platforms :jruby do
gem "jruby-openssl"
end
ruby-samuel-0.3.3/LICENSE 0000664 0000000 0000000 00000002046 12152633241 0014770 0 ustar 00root root 0000000 0000000 Copyright 2009–2011 Chris Kampmeier
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
ruby-samuel-0.3.3/README.rdoc 0000664 0000000 0000000 00000006662 12152633241 0015601 0 ustar 00root root 0000000 0000000 = Samuel
Samuel is a gem for automatic logging of your HTTP requests. It's named for
the serial diarist Mr. Pepys, who was known to reliably record events both
quotidian and remarkable.
Should a Great Plague, Fire, or Whale befall an important external web service
you use, you'll be sure to have a tidy record of it.
It supports both Net::HTTP and HTTPClient (formerly HTTPAccess2),
automatically loading the correct logger for the HTTP client you're using.
== Usage
If you're using Bundler, just add this to your Gemfile:
gem "samuel", "~> 0.3"
When Rails is loaded, Samuel configures itself to use Rails's logger and an
ActiveRecord-like format automatically, so you don't need to do anything else.
For non-Rails projects, you'll have to manually configure logging, like this:
require 'samuel'
Samuel.logger = Logger.new('http_requests.log')
If you don't assign a logger, Samuel will configure a default logger on +STDOUT+.
== HTTP Clients
When you load Samuel, it automatically detects which HTTP clients you've
loaded, then patches them to add logging. If no HTTP drivers are loaded when
you load Samuel, it will automatically load Net::HTTP for you. (So, if you're
using HTTPClient or a library based on it, make sure to require it before you
require Samuel.)
== Configuration
There are two ways to specify configuration options for Samuel: global and
inline. Global configs look like this:
Samuel.config[:labels] = {"example.com" => "Example API"}
Samuel.config[:filtered_params] = :password
You should put global configuration somewhere early-on in your program. If
you're using Rails, config/initializers/samuel.rb will do the trick.
Alternatively, an inline configuration block temporarily overrides any global
configuration for a set of HTTP requests:
Samuel.with_config :label => "Twitter API" do
Net::HTTP.start("twitter.com") { |http| http.get("/help/test") }
end
Right now, there are three configuration changes you can make in either style:
* :labels -- This is a hash with domain substrings as keys and log
labels as values. If a request domain includes one of the domain substrings,
the corresponding label will be used for the first part of that log entry.
By default this is empty, so that all requests are labeled with a default of
"HTTP Request".
* :label -- As an alternative to the :labels hash, this is
simply a string. If set, it takes precedence over any :labels (by
default, it's not set). It gets "Request" appended to it as well --
so if you want your log to always say Twitter API Request instead
of the default HTTP Request, you can set this to "Twitter
API". I'd recommend using this setting globally if you're only making
requests to one service, or inline if you just need to temporarily override
the global :labels.
* :filtered_params -- This works just like Rails's
+filter_parameter_logging+ method. Set it to a symbol, string, or array of
them, and Samuel will filter the value of query parameters that have any of
these patterns as a substring by replacing the value with
[FILTERED] in your logs. By default, no filtering is enabled.
Samuel logs successful HTTP requests at the +INFO+ level; Failed requests log
at the +WARN+ level. This isn't currently configurable, but it's on the list.
== License
Copyright 2009–2011 Chris Kampmeier. See +LICENSE+ for details.
ruby-samuel-0.3.3/Rakefile 0000664 0000000 0000000 00000001514 12152633241 0015427 0 ustar 00root root 0000000 0000000 require 'rubygems'
require 'rake'
task :check_dependencies do
begin
require "bundler"
rescue LoadError
abort "Samuel uses Bundler to manage development dependencies. Install it with `gem install bundler`."
end
system("bundle check") || abort
end
require 'rake/testtask'
Rake::TestTask.new(:test) do |test|
test.libs << 'lib' << 'test'
test.pattern = 'test/**/*_test.rb'
test.verbose = false
test.warning = true
end
task :default => [:check_dependencies, :test]
begin
require 'rcov/rcovtask'
Rcov::RcovTask.new do |test|
test.libs << 'test'
test.pattern = 'test/**/*_test.rb'
test.rcov_opts << "--sort coverage"
test.rcov_opts << "--exclude gems"
test.verbose = false
test.warning = true
end
rescue LoadError
end
begin
require 'yard'
YARD::Rake::YardocTask.new
rescue LoadError
end
ruby-samuel-0.3.3/lib/ 0000775 0000000 0000000 00000000000 12152633241 0014527 5 ustar 00root root 0000000 0000000 ruby-samuel-0.3.3/lib/samuel.rb 0000664 0000000 0000000 00000002230 12152633241 0016337 0 ustar 00root root 0000000 0000000 require "logger"
require "forwardable"
require "samuel/loader"
require "samuel/diary"
require "samuel/driver_patches/http_client"
require "samuel/driver_patches/net_http"
require "samuel/log_entries/base"
require "samuel/log_entries/http_client"
require "samuel/log_entries/net_http"
module Samuel
extend self
VERSION = "0.3.3"
attr_writer :logger, :config
def logger
@logger = nil if !defined?(@logger)
return @logger if !@logger.nil?
if defined?(Rails) && Rails.respond_to?(:logger)
@logger = Rails.logger
else
@logger = Logger.new(STDOUT)
end
end
def config
Thread.current[:__samuel_config] ? Thread.current[:__samuel_config] : @config
end
def with_config(options = {})
original_config = config.dup
nested = !Thread.current[:__samuel_config].nil?
Thread.current[:__samuel_config] = original_config.merge(options)
yield
Thread.current[:__samuel_config] = nested ? original_config : nil
end
def reset_config
Thread.current[:__samuel_config] = nil
@config = {:label => nil, :labels => {}, :filtered_params => []}
end
end
Samuel.reset_config
Samuel::Loader.apply_driver_patches
ruby-samuel-0.3.3/lib/samuel/ 0000775 0000000 0000000 00000000000 12152633241 0016015 5 ustar 00root root 0000000 0000000 ruby-samuel-0.3.3/lib/samuel/diary.rb 0000664 0000000 0000000 00000001765 12152633241 0017463 0 ustar 00root root 0000000 0000000 module Samuel
module Diary
extend self
def record_request(http, request, time_requested = current_time)
@requests ||= []
@requests.push({:request => request, :time_requested => time_requested})
end
def record_response(http, request, response, time_responded = current_time)
time_requested = @requests.detect { |r| r[:request] == request }[:time_requested]
@requests.reject! { |r| r[:request] == request }
log_request_and_response(http, request, response, time_requested, time_responded)
end
def current_time
Time.now
end
private
def log_request_and_response(http, request, response, time_started, time_ended)
log_entry_class = case http.class.to_s
when "Net::HTTP" then LogEntries::NetHttp
when "HTTPClient" then LogEntries::HttpClient
else raise NotImplementedError
end
log_entry = log_entry_class.new(http, request, response, time_started, time_ended)
log_entry.log!
end
end
end
ruby-samuel-0.3.3/lib/samuel/driver_patches/ 0000775 0000000 0000000 00000000000 12152633241 0021017 5 ustar 00root root 0000000 0000000 ruby-samuel-0.3.3/lib/samuel/driver_patches/http_client.rb 0000664 0000000 0000000 00000002743 12152633241 0023667 0 ustar 00root root 0000000 0000000 module Samuel
module DriverPatches
module HTTPClient
def self.included(klass)
methods_to_wrap = %w(initialize do_get_block do_get_stream)
methods_to_wrap.each do |method|
klass.send(:alias_method, "#{method}_without_samuel", method)
klass.send(:alias_method, method, "#{method}_with_samuel")
end
end
def initialize_with_samuel(*args)
initialize_without_samuel(*args)
@request_filter << LoggingFilter.new(self)
end
def do_get_block_with_samuel(req, proxy, conn, &block)
begin
do_get_block_without_samuel(req, proxy, conn, &block)
rescue Exception => e
Samuel::Diary.record_response(self, req, e)
raise
end
end
def do_get_stream_with_samuel(req, proxy, conn)
begin
do_get_stream_without_samuel(req, proxy, conn)
rescue Exception => e
Samuel::Diary.record_response(self, req, e)
raise
end
end
class LoggingFilter
def initialize(http_client_instance)
@http_client_instance = http_client_instance
end
def filter_request(request)
Samuel::Diary.record_request(@http_client_instance, request)
end
def filter_response(request, response)
Samuel::Diary.record_response(@http_client_instance, request, response)
nil # this returns command symbols like :retry, etc.
end
end
end
end
end
ruby-samuel-0.3.3/lib/samuel/driver_patches/net_http.rb 0000664 0000000 0000000 00000002336 12152633241 0023175 0 ustar 00root root 0000000 0000000 module Samuel
module DriverPatches
module NetHTTP
def self.included(klass)
methods_to_wrap = %w(request connect)
methods_to_wrap.each do |method|
klass.send(:alias_method, "#{method}_without_samuel", method)
klass.send(:alias_method, method, "#{method}_with_samuel")
end
end
def request_with_samuel(request, body = nil, &block)
response, exception_raised = nil, false
request_time = Samuel::Diary.current_time
begin
response = request_without_samuel(request, body, &block)
rescue Exception => response
exception_raised = true
end
Samuel::Diary.record_request(self, request, request_time)
Samuel::Diary.record_response(self, request, response)
raise response if exception_raised
response
end
def connect_with_samuel
connect_without_samuel
rescue Exception => response
fake_request = Object.new
def fake_request.path; ""; end
def fake_request.method; "CONNECT"; end
Samuel::Diary.record_request(self, fake_request)
Samuel::Diary.record_response(self, fake_request, response)
raise
end
end
end
end
ruby-samuel-0.3.3/lib/samuel/loader.rb 0000664 0000000 0000000 00000000714 12152633241 0017612 0 ustar 00root root 0000000 0000000 module Samuel
module Loader
extend self
def apply_driver_patches
loaded = { :net_http => defined?(Net::HTTP),
:http_client => defined?(HTTPClient) }
Net::HTTP.send(:include, DriverPatches::NetHTTP) if loaded[:net_http]
HTTPClient.send(:include, DriverPatches::HTTPClient) if loaded[:http_client]
if loaded.values.none?
require 'net/http'
apply_driver_patches
end
end
end
end
ruby-samuel-0.3.3/lib/samuel/log_entries/ 0000775 0000000 0000000 00000000000 12152633241 0020327 5 ustar 00root root 0000000 0000000 ruby-samuel-0.3.3/lib/samuel/log_entries/base.rb 0000664 0000000 0000000 00000003537 12152633241 0021576 0 ustar 00root root 0000000 0000000 module Samuel
module LogEntries
class Base
def initialize(http, request, response, time_requested, time_responded)
@http, @request, @response = http, request, response
@seconds = time_responded - time_requested
end
def log!
Samuel.logger.add(log_level, log_message)
end
protected
def log_message
bold = "\e[1m"
blue = "\e[34m"
underline = "\e[4m"
reset = "\e[0m"
" #{bold}#{blue}#{underline}#{label} request (#{milliseconds}ms) " +
"#{response_summary}#{reset} #{method} #{uri}"
end
def milliseconds
(@seconds * 1000).round
end
def uri
"#{scheme}://#{host}#{port_if_not_default}#{path}#{'?' if query}#{filtered_query}"
end
def label
return Samuel.config[:label] if Samuel.config[:label]
default = lambda { ["", "HTTP"] }
Samuel.config[:labels].detect(default) { |domain, label|
host.include?(domain)
}[1]
end
def response_summary
if @response.is_a?(Exception)
@response.class
else
"[#{status_code} #{status_message}]"
end
end
def log_level
error? ? Logger::WARN : Logger::INFO
end
def ssl?
scheme == 'https'
end
def filtered_query
return "" if query.nil?
patterns = [Samuel.config[:filtered_params]].flatten
patterns.map { |pattern|
pattern_for_regex = Regexp.escape(pattern.to_s)
[/([^&]*#{pattern_for_regex}[^&=]*)=(?:[^&]+)/, '\1=[FILTERED]']
}.inject(query) { |filtered, filter| filtered.gsub(*filter) }
end
def port_if_not_default
if (!ssl? && port == 80) || (ssl? && port == 443)
""
else
":#{port}"
end
end
end
end
end
ruby-samuel-0.3.3/lib/samuel/log_entries/http_client.rb 0000664 0000000 0000000 00000001013 12152633241 0023164 0 ustar 00root root 0000000 0000000 module Samuel
module LogEntries
class HttpClient < Base
extend Forwardable
def_delegators :"@request.header.request_uri",
:host, :path, :query, :scheme, :port
def method
@request.header.request_method
end
def status_code
@response.status
end
def status_message
@response.header.reason_phrase.strip
end
def error?
@response.is_a?(Exception) || @response.status.to_s =~ /^(4|5)/
end
end
end
end
ruby-samuel-0.3.3/lib/samuel/log_entries/net_http.rb 0000664 0000000 0000000 00000001420 12152633241 0022476 0 ustar 00root root 0000000 0000000 module Samuel
module LogEntries
class NetHttp < Base
def host
@http.address
end
def path
@request.path.split("?")[0]
end
def query
@request.path.split("?")[1]
end
def scheme
@http.use_ssl? ? "https" : "http"
end
def port
@http.port
end
def method
@request.method.to_s.upcase
end
def status_code
@response.code
end
def status_message
@response.message.strip
end
def error?
error_classes = %w(Exception Net::HTTPClientError Net::HTTPServerError)
response_ancestors = @response.class.ancestors.map { |a| a.to_s }
(error_classes & response_ancestors).any?
end
end
end
end
ruby-samuel-0.3.3/metadata.yml 0000664 0000000 0000000 00000010330 12152633241 0016261 0 ustar 00root root 0000000 0000000 --- !ruby/object:Gem::Specification
name: samuel
version: !ruby/object:Gem::Version
hash: 21
prerelease:
segments:
- 0
- 3
- 3
version: 0.3.3
platform: ruby
authors:
- Chris Kampmeier
autorequire:
bindir: bin
cert_chain: []
date: 2011-11-10 00:00:00 -08:00
default_executable:
dependencies:
- !ruby/object:Gem::Dependency
name: shoulda
prerelease: false
requirement: &id001 !ruby/object:Gem::Requirement
none: false
requirements:
- - "="
- !ruby/object:Gem::Version
hash: 37
segments:
- 2
- 11
- 3
version: 2.11.3
type: :development
version_requirements: *id001
- !ruby/object:Gem::Dependency
name: mocha
prerelease: false
requirement: &id002 !ruby/object:Gem::Requirement
none: false
requirements:
- - "="
- !ruby/object:Gem::Version
hash: 55
segments:
- 0
- 10
- 0
version: 0.10.0
type: :development
version_requirements: *id002
- !ruby/object:Gem::Dependency
name: httpclient
prerelease: false
requirement: &id003 !ruby/object:Gem::Requirement
none: false
requirements:
- - "="
- !ruby/object:Gem::Version
hash: 1
segments:
- 2
- 2
- 3
version: 2.2.3
type: :development
version_requirements: *id003
- !ruby/object:Gem::Dependency
name: fakeweb
prerelease: false
requirement: &id004 !ruby/object:Gem::Requirement
none: false
requirements:
- - ~>
- !ruby/object:Gem::Version
hash: 9
segments:
- 1
- 3
version: "1.3"
type: :development
version_requirements: *id004
- !ruby/object:Gem::Dependency
name: rcov
prerelease: false
requirement: &id005 !ruby/object:Gem::Requirement
none: false
requirements:
- - "="
- !ruby/object:Gem::Version
hash: 45
segments:
- 0
- 9
- 11
version: 0.9.11
type: :development
version_requirements: *id005
- !ruby/object:Gem::Dependency
name: yard
prerelease: false
requirement: &id006 !ruby/object:Gem::Requirement
none: false
requirements:
- - "="
- !ruby/object:Gem::Version
hash: 5
segments:
- 0
- 7
- 3
version: 0.7.3
type: :development
version_requirements: *id006
- !ruby/object:Gem::Dependency
name: rake
prerelease: false
requirement: &id007 !ruby/object:Gem::Requirement
none: false
requirements:
- - "="
- !ruby/object:Gem::Version
hash: 11
segments:
- 0
- 9
- 2
- 2
version: 0.9.2.2
type: :development
version_requirements: *id007
description: An automatic logger for HTTP requests in Ruby, supporting the Net::HTTP and HTTPClient client libraries.
email: chris@kampers.net
executables: []
extensions: []
extra_rdoc_files:
- LICENSE
- README.rdoc
files:
- .document
- .gitignore
- Gemfile
- LICENSE
- README.rdoc
- Rakefile
- lib/samuel.rb
- lib/samuel/diary.rb
- lib/samuel/driver_patches/http_client.rb
- lib/samuel/driver_patches/net_http.rb
- lib/samuel/loader.rb
- lib/samuel/log_entries/base.rb
- lib/samuel/log_entries/http_client.rb
- lib/samuel/log_entries/net_http.rb
- samuel.gemspec
- test/http_client_test.rb
- test/loader_test.rb
- test/net_http_test.rb
- test/samuel_test.rb
- test/test_helper.rb
- test/thread_test.rb
has_rdoc: true
homepage: http://github.com/chrisk/samuel
licenses: []
post_install_message:
rdoc_options:
- --charset=UTF-8
require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
none: false
requirements:
- - ">="
- !ruby/object:Gem::Version
hash: 3
segments:
- 0
version: "0"
required_rubygems_version: !ruby/object:Gem::Requirement
none: false
requirements:
- - ">="
- !ruby/object:Gem::Version
hash: 3
segments:
- 0
version: "0"
requirements: []
rubyforge_project: samuel
rubygems_version: 1.6.2
signing_key:
specification_version: 3
summary: An automatic logger for HTTP requests in Ruby
test_files:
- test/http_client_test.rb
- test/loader_test.rb
- test/net_http_test.rb
- test/samuel_test.rb
- test/test_helper.rb
- test/thread_test.rb
ruby-samuel-0.3.3/samuel.gemspec 0000664 0000000 0000000 00000003644 12152633241 0016623 0 ustar 00root root 0000000 0000000 # encoding: utf-8
Gem::Specification.new do |s|
s.name = %q{samuel}
s.version = "0.3.3"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Chris Kampmeier"]
s.date = %q{2011-11-10}
s.description = %q{An automatic logger for HTTP requests in Ruby, supporting the Net::HTTP and HTTPClient client libraries.}
s.email = %q{chris@kampers.net}
s.extra_rdoc_files = [
"LICENSE",
"README.rdoc"
]
s.files = [
".document",
".gitignore",
"Gemfile",
"LICENSE",
"README.rdoc",
"Rakefile",
"lib/samuel.rb",
"lib/samuel/diary.rb",
"lib/samuel/driver_patches/http_client.rb",
"lib/samuel/driver_patches/net_http.rb",
"lib/samuel/loader.rb",
"lib/samuel/log_entries/base.rb",
"lib/samuel/log_entries/http_client.rb",
"lib/samuel/log_entries/net_http.rb",
"samuel.gemspec",
"test/http_client_test.rb",
"test/loader_test.rb",
"test/net_http_test.rb",
"test/samuel_test.rb",
"test/test_helper.rb",
"test/thread_test.rb"
]
s.homepage = %q{http://github.com/chrisk/samuel}
s.rdoc_options = ["--charset=UTF-8"]
s.require_paths = ["lib"]
s.rubyforge_project = %q{samuel}
s.rubygems_version = %q{1.3.5}
s.summary = %q{An automatic logger for HTTP requests in Ruby}
s.test_files = [
"test/http_client_test.rb",
"test/loader_test.rb",
"test/net_http_test.rb",
"test/samuel_test.rb",
"test/test_helper.rb",
"test/thread_test.rb"
]
s.specification_version = 3
s.add_development_dependency("shoulda", ["2.11.3"])
s.add_development_dependency("mocha", ["0.10.0"])
s.add_development_dependency("httpclient", ["2.2.3"])
s.add_development_dependency("fakeweb", ["~> 1.3"])
s.add_development_dependency("rcov", ["0.9.11"])
s.add_development_dependency("yard", ["0.7.3"])
s.add_development_dependency("rake", ["0.9.2.2"])
end
ruby-samuel-0.3.3/test/ 0000775 0000000 0000000 00000000000 12152633241 0014740 5 ustar 00root root 0000000 0000000 ruby-samuel-0.3.3/test/http_client_test.rb 0000664 0000000 0000000 00000005374 12152633241 0020652 0 ustar 00root root 0000000 0000000 require 'test_helper'
class HttpClientTest < Test::Unit::TestCase
context "making an HTTPClient request" do
setup { setup_test_logger
start_test_server
Samuel.reset_config }
teardown { teardown_test_logger }
context "to GET http://localhost:8000/, responding with a 200 in 53ms" do
setup do
now = Time.now
Samuel::Diary.stubs(:current_time).returns(now, now + 0.053)
HTTPClient.get("http://localhost:8000/")
end
should_log_lines 1
should_log_at_level :info
should_log_including "HTTP request"
should_log_including "(53ms)"
should_log_including "[200 OK]"
should_log_including "GET http://localhost:8000/"
end
context "using PUT" do
setup do
HTTPClient.put("http://localhost:8000/books/1", "test=true")
end
should_log_including "PUT http://localhost:8000/books/1"
end
context "using an asynchronous POST" do
setup do
body = "title=Infinite%20Jest"
client = HTTPClient.new
connection = client.post_async("http://localhost:8000/books", body)
sleep 0.1 until connection.finished?
end
should_log_including "POST http://localhost:8000/books"
end
context "that raises" do
setup do
begin
HTTPClient.get("http://localhost:8001/")
rescue Errno::ECONNREFUSED => @exception
end
end
should_log_at_level :warn
should_log_including "HTTP request"
should_log_including "GET http://localhost:8001/"
should_log_including "Errno::ECONNREFUSED"
should_log_including %r|\d+ms|
should_raise_exception Errno::ECONNREFUSED
end
context "using an asynchronous GET that raises" do
setup do
begin
client = HTTPClient.new
connection = client.get_async("http://localhost:8001/")
sleep 0.1 until connection.finished?
connection.pop
rescue Errno::ECONNREFUSED => @exception
end
end
should_log_at_level :warn
should_log_including "HTTP request"
should_log_including "GET http://localhost:8001/"
should_log_including "Errno::ECONNREFUSED"
should_log_including %r|\d+ms|
should_raise_exception Errno::ECONNREFUSED
end
context "that responds with a 400-level code" do
setup do
HTTPClient.get("http://localhost:8000/test?404")
end
should_log_at_level :warn
should_log_including "[404 Not Found]"
end
context "that responds with a 500-level code" do
setup do
HTTPClient.get("http://localhost:8000/test?500")
end
should_log_at_level :warn
should_log_including "[500 Internal Server Error]"
end
end
end
ruby-samuel-0.3.3/test/loader_test.rb 0000664 0000000 0000000 00000003600 12152633241 0017571 0 ustar 00root root 0000000 0000000 require 'test_helper'
class LoaderTest < Test::Unit::TestCase
def capture_output(code = "")
requires = @requires.map { |lib| "require '#{lib}';" }.join(' ')
samuel_dir = "#{File.dirname(__FILE__)}/../lib"
`#{ruby_path} -I#{samuel_dir} -e "#{requires} #{code}" 2>&1`
end
context "loading Samuel" do
setup do
start_test_server
@requires = ['samuel']
end
context "when no HTTP drivers are loaded" do
should "automatically load Net::HTTP" do
output = capture_output "puts defined?(Net::HTTP)"
assert_equal "constant", output.strip
end
should "successfully log a Net::HTTP request" do
output = capture_output "Net::HTTP.get(URI.parse('http://localhost:8000'))"
assert_match %r[HTTP request], output
end
should "not load HTTPClient" do
output = capture_output "puts 'good' unless defined?(HTTPClient)"
assert_equal "good", output.strip
end
end
context "when Net::HTTP is already loaded" do
setup { @requires.unshift('net/http') }
should "successfully log a Net::HTTP request" do
output = capture_output "Net::HTTP.get(URI.parse('http://localhost:8000'))"
assert_match %r[HTTP request], output
end
should "not load HTTPClient" do
output = capture_output "puts 'good' unless defined?(HTTPClient)"
assert_match "good", output.strip
end
end
context "when HTTPClient is already loaded" do
setup { @requires.unshift('rubygems', 'httpclient') }
should "successfully log an HTTPClient request" do
output = capture_output "HTTPClient.get('http://localhost:8000')"
assert_match %r[HTTP request], output
end
should "not load Net::HTTP" do
output = capture_output "puts 'good' unless defined?(Net::HTTP)"
assert_match "good", output.strip
end
end
end
end
ruby-samuel-0.3.3/test/net_http_test.rb 0000664 0000000 0000000 00000017615 12152633241 0020163 0 ustar 00root root 0000000 0000000 require 'test_helper'
class RequestTest < Test::Unit::TestCase
context "making an HTTP request" do
setup { setup_test_logger
FakeWeb.clean_registry
Samuel.reset_config }
teardown { teardown_test_logger }
context "to GET http://example.com/test, responding with a 200 in 53ms" do
setup do
FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
now = Time.now
Samuel::Diary.stubs(:current_time).returns(now, now + 0.053)
open "http://example.com/test"
end
should_log_lines 1
should_log_at_level :info
should_log_including "HTTP request"
should_log_including "(53ms)"
should_log_including "[200 OK]"
should_log_including "GET http://example.com/test"
end
context "on a non-standard port" do
setup do
FakeWeb.register_uri(:get, "http://example.com:8080/test", :status => [200, "OK"])
open "http://example.com:8080/test"
end
should_log_including "GET http://example.com:8080/test"
end
context "with SSL" do
setup do
FakeWeb.register_uri(:get, "https://example.com/test", :status => [200, "OK"])
open "https://example.com/test"
end
should_log_including "HTTP request"
should_log_including "GET https://example.com/test"
end
context "with SSL on a non-standard port" do
setup do
FakeWeb.register_uri(:get, "https://example.com:80/test", :status => [200, "OK"])
open "https://example.com:80/test"
end
should_log_including "HTTP request"
should_log_including "GET https://example.com:80/test"
end
context "that raises" do
setup do
FakeWeb.register_uri(:get, "http://example.com/test", :exception => Errno::ECONNREFUSED)
begin
Net::HTTP.start("example.com") { |http| http.get("/test") }
rescue Exception => @exception
end
end
should_log_at_level :warn
should_log_including "HTTP request"
should_log_including "GET http://example.com/test"
should_log_including "Errno::ECONNREFUSED"
should_log_including %r|\d+ms|
should_raise_exception Errno::ECONNREFUSED
end
context "that raises a SocketError when connecting" do
setup do
FakeWeb.allow_net_connect = true
begin
http = Net::HTTP.new("example.com")
# This is an implementation-dependent hack; it would be more correct
# to stub out TCPSocket.open, but I can't get Mocha to make it raise
# correctly. Maybe related to TCPSocket being native code?
http.stubs(:connect_without_samuel).raises(SocketError)
http.start { |h| h.get("/test") }
rescue Exception => @exception
end
end
teardown do
FakeWeb.allow_net_connect = false
end
should_log_at_level :warn
should_log_including "HTTP request"
should_log_including "CONNECT http://example.com"
should_log_including "SocketError"
should_log_including %r|\d+ms|
should_raise_exception SocketError
end
context "that responds with a 500-level code" do
setup do
FakeWeb.register_uri(:get, "http://example.com/test", :status => [502, "Bad Gateway"])
Net::HTTP.start("example.com") { |http| http.get("/test") }
end
should_log_at_level :warn
end
context "that responds with a 400-level code" do
setup do
FakeWeb.register_uri(:get, "http://example.com/test", :status => [404, "Not Found"])
Net::HTTP.start("example.com") { |http| http.get("/test") }
end
should_log_at_level :warn
end
context "inside a configuration block with :label => 'Example'" do
setup do
FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
Samuel.with_config :label => "Example" do
open "http://example.com/test"
end
end
should_log_including "Example request"
should_have_config_afterwards_including :labels => {}, :label => nil
end
context "inside a configuration block with :filter_params" do
setup do
FakeWeb.register_uri(:get, "http://example.com/test?password=secret&username=chrisk",
:status => [200, "OK"])
@uri = "http://example.com/test?password=secret&username=chrisk"
end
context "=> :password" do
setup { Samuel.with_config(:filtered_params => :password) { open @uri } }
should_log_including "http://example.com/test?password=[FILTERED]&username=chrisk"
end
context "=> :as" do
setup { Samuel.with_config(:filtered_params => :ass) { open @uri } }
should_log_including "http://example.com/test?password=[FILTERED]&username=chrisk"
end
context "=> ['pass', 'name']" do
setup { Samuel.with_config(:filtered_params => %w(pass name)) { open @uri } }
should_log_including "http://example.com/test?password=[FILTERED]&username=[FILTERED]"
end
end
context "with a global config including :label => 'Example'" do
setup do
FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
Samuel.config[:label] = "Example"
open "http://example.com/test"
end
should_log_including "Example request"
should_have_config_afterwards_including :labels => {}, :label => "Example"
end
context "with a global config including :label => 'Example' but inside config block that changes it to 'Example 2'" do
setup do
FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
Samuel.config[:label] = "Example"
Samuel.with_config(:label => "Example 2") { open "http://example.com/test" }
end
should_log_including "Example 2 request"
should_have_config_afterwards_including :labels => {}, :label => "Example"
end
context "inside a config block of :label => 'Example 2' nested inside a config block of :label => 'Example'" do
setup do
FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
Samuel.with_config :label => "Example" do
Samuel.with_config :label => "Example 2" do
open "http://example.com/test"
end
end
end
should_log_including "Example 2 request"
should_have_config_afterwards_including :labels => {}, :label => nil
end
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
setup do
FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
Samuel.config[:labels] = {'example.com' => 'Example'}
Samuel.with_config :label => "Example 2" do
Samuel.with_config :label => "Example 3" do
open "http://example.com/test"
end
end
end
should_log_including "Example 3 request"
should_have_config_afterwards_including :labels => {'example.com' => 'Example'},
:label => nil
end
context "with a global config including :labels => {'example.com' => 'Example API'}" do
setup do
FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
Samuel.config[:labels] = {'example.com' => 'Example API'}
open "http://example.com/test"
end
should_log_including "Example API request"
end
context "with a global config including :labels => {'example.org' => 'Example API'} but making a request to example.com" do
setup do
FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
Samuel.config[:labels] = {'example.org' => 'Example API'}
open "http://example.com/test"
end
should_log_including "HTTP request"
end
end
end
ruby-samuel-0.3.3/test/samuel_test.rb 0000664 0000000 0000000 00000002000 12152633241 0017602 0 ustar 00root root 0000000 0000000 require 'test_helper'
class SamuelTest < Test::Unit::TestCase
context "logger configuration" do
setup do
Samuel.logger = nil
Object.send(:remove_const, :Rails) if Object.const_defined?(:Rails)
end
teardown do
Samuel.logger = nil
end
context "when Rails's logger is available" do
setup { Object.const_set(:Rails, stub(:logger => :mock_logger)) }
should "use the same logger" do
assert_equal :mock_logger, Samuel.logger
end
end
context "when Rails's logger is not available" do
should "use a new Logger instance pointed to STDOUT" do
assert_instance_of Logger, Samuel.logger
assert_equal STDOUT, Samuel.logger.instance_variable_get(:"@logdev").dev
end
end
end
context ".reset_config" do
should "reset the config to default vaules" do
Samuel.config = {:foo => "bar"}
Samuel.reset_config
assert_equal({:label => nil, :labels => {}, :filtered_params => []}, Samuel.config)
end
end
end
ruby-samuel-0.3.3/test/test_helper.rb 0000664 0000000 0000000 00000005263 12152633241 0017611 0 ustar 00root root 0000000 0000000 require 'rubygems'
require 'bundler'
Bundler.setup
require 'shoulda'
require 'mocha'
require 'net/http'
require 'httpclient'
require 'open-uri'
require 'fakeweb'
require 'webrick'
require 'samuel'
FakeWeb.allow_net_connect = false
class Test::Unit::TestCase
TEST_LOG_PATH = File.join(File.dirname(__FILE__), 'test.log')
def self.should_log_lines(expected_count)
should "log #{expected_count} line#{'s' unless expected_count == 1}" do
lines = File.readlines(TEST_LOG_PATH)
assert_equal expected_count, lines.length
end
end
def self.should_log_including(what)
should "log a line including #{what.inspect}" do
contents = File.read(TEST_LOG_PATH)
if what.is_a?(Regexp)
assert_match what, contents
else
assert contents.include?(what),
"Expected #{contents.inspect} to include #{what.inspect}"
end
end
end
def self.should_log_at_level(level)
level = level.to_s.upcase
should "log at the #{level} level" do
assert File.read(TEST_LOG_PATH).include?(" #{level} -- :")
end
end
def self.should_raise_exception(klass)
should "raise an #{klass} exception" do
@exception = nil if !defined?(@exception)
assert @exception.is_a?(klass)
end
end
def self.should_have_config_afterwards_including(config)
config.each_pair do |key, value|
should "continue afterwards with Samuel.config[#{key.inspect}] set to #{value.inspect}" do
assert_equal value, Samuel.config[key]
end
end
end
# The path to the current ruby interpreter. Adapted from Rake's FileUtils.
def ruby_path
ext = ((RbConfig::CONFIG['ruby_install_name'] =~ /\.(com|cmd|exe|bat|rb|sh)$/) ? "" : RbConfig::CONFIG['EXEEXT'])
File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'] + ext).sub(/.*\s.*/m, '"\&"')
end
def setup_test_logger
FileUtils.rm_rf TEST_LOG_PATH
FileUtils.touch TEST_LOG_PATH
Samuel.logger = Logger.new(TEST_LOG_PATH)
end
def teardown_test_logger
FileUtils.rm_rf TEST_LOG_PATH
end
def start_test_server
return if defined?(@@server)
@@server = WEBrick::HTTPServer.new(
:Port => 8000, :AccessLog => [],
:Logger => WEBrick::Log.new(nil, WEBrick::BasicLog::WARN)
)
@@server.mount "/", ResponseCodeServer
at_exit { @@server.shutdown }
Thread.new { @@server.start }
end
end
class ResponseCodeServer < WEBrick::HTTPServlet::AbstractServlet
def do_GET(request, response)
response_code = request.query_string.nil? ? 200 : request.query_string.to_i
response.status = response_code
end
alias_method :do_POST, :do_GET
alias_method :do_PUT, :do_GET
alias_method :do_DELETE, :do_GET
end
ruby-samuel-0.3.3/test/thread_test.rb 0000664 0000000 0000000 00000001511 12152633241 0017571 0 ustar 00root root 0000000 0000000 require 'test_helper'
class ThreadTest < Test::Unit::TestCase
context "when logging multiple requests at once" do
setup do
@log = StringIO.new
Samuel.logger = Logger.new(@log)
FakeWeb.register_uri(:get, /example\.com/, :status => [200, "OK"])
threads = []
5.times do |i|
threads << Thread.new(i) do |n|
Samuel.with_config :label => "Example #{n}" do
Thread.pass
open "http://example.com/#{n}"
end
end
end
threads.each { |t| t.join }
@log.rewind
end
should "not let configuration blocks interfere with eachother" do
@log.each_line do |line|
matches = %r|Example (\d+).*example\.com/(\d+)|.match(line)
assert_not_nil matches
assert_equal matches[1], matches[2]
end
end
end
end