sham_rack 1.1.2 → 1.2.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.
- data/CHANGES.markdown +4 -0
- data/README.markdown +4 -2
- data/Rakefile +33 -15
- data/benchmark/benchmark.rb +49 -0
- data/benchmark/hello_app.rb +10 -0
- data/lib/sham_rack.rb +1 -0
- data/lib/sham_rack/core_ext/net/http.rb +10 -7
- data/lib/sham_rack/http.rb +85 -104
- data/lib/sham_rack/version.rb +3 -0
- data/sham_rack.gemspec +10 -5
- data/spec/sham_rack_spec.rb +11 -0
- metadata +6 -4
- data/VERSION.yml +0 -4
data/CHANGES.markdown
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
## 27-Nov-2009 [mdub@dogbiscuit.org]
|
2
|
+
|
3
|
+
* Change of approach: extend rather than reimplement Net:HTTP. This should improve coverage of all the weird and wonderful ways of using the Net:HTTP API.
|
4
|
+
|
1
5
|
## 5-Jun-2009 [mdub@dogbiscuit.org]
|
2
6
|
|
3
7
|
* Add support for Net::HTTP.get_response.
|
data/README.markdown
CHANGED
@@ -6,14 +6,16 @@ ShamRack plumbs Net:HTTP into [Rack][rack].
|
|
6
6
|
What's it for, again?
|
7
7
|
---------------------
|
8
8
|
|
9
|
-
Well,
|
9
|
+
Well, it makes it easy to _stub out external (HTTP) services_, which is handy in development and testing environments, or when you want to _test your HTTP client code_.
|
10
10
|
|
11
|
-
|
11
|
+
You can also use it to _test your Rack application_ (or Sinatra, or Rails, or Merb) using arbitrary HTTP client libraries, to check interoperability. For instance, you could test your app using:
|
12
12
|
|
13
13
|
* [`rest-client`][rest-client]
|
14
14
|
* [`httparty`][httparty]
|
15
15
|
* [`oauth`][oauth]
|
16
16
|
|
17
|
+
all without having to boot it in a server.
|
18
|
+
|
17
19
|
Installing it
|
18
20
|
-------------
|
19
21
|
|
data/Rakefile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "rake"
|
3
3
|
|
4
|
+
require File.dirname(__FILE__) + "/lib/sham_rack/version.rb"
|
5
|
+
|
4
6
|
require "spec/rake/spectask"
|
5
7
|
|
6
8
|
task "default" => "spec"
|
@@ -10,21 +12,8 @@ Spec::Rake::SpecTask.new do |t|
|
|
10
12
|
t.spec_files = FileList['spec/**/*_spec.rb']
|
11
13
|
end
|
12
14
|
|
13
|
-
require "jeweler"
|
14
|
-
|
15
|
-
Jeweler::Tasks.new do |g|
|
16
|
-
g.name = "sham_rack"
|
17
|
-
g.summary = "Net::HTTP-to-Rack plumbing"
|
18
|
-
g.email = "mdub@dogbiscuit.org"
|
19
|
-
g.homepage = "http://github.com/mdub/sham_rack"
|
20
|
-
g.description = "ShamRack plumbs Net::HTTP directly into Rack, for quick and easy HTTP testing."
|
21
|
-
g.authors = ["Mike Williams"]
|
22
|
-
g.rubyforge_project = "shamrack"
|
23
|
-
end
|
24
|
-
|
25
|
-
Jeweler::RubyforgeTasks.new
|
26
|
-
|
27
15
|
require 'rake/rdoctask'
|
16
|
+
|
28
17
|
Rake::RDocTask.new do |rdoc|
|
29
18
|
if File.exist?('VERSION.yml')
|
30
19
|
config = YAML.load(File.read('VERSION.yml'))
|
@@ -34,7 +23,36 @@ Rake::RDocTask.new do |rdoc|
|
|
34
23
|
end
|
35
24
|
|
36
25
|
rdoc.rdoc_dir = 'rdoc'
|
37
|
-
rdoc.title = "ShamRack #{
|
26
|
+
rdoc.title = "ShamRack #{ShamRack::VERSION}"
|
38
27
|
rdoc.main = "ShamRack"
|
39
28
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
40
29
|
end
|
30
|
+
|
31
|
+
def after_requiring(lib, options = {})
|
32
|
+
begin
|
33
|
+
require(lib)
|
34
|
+
rescue LoadError
|
35
|
+
gem_name = options[:gem] || lib
|
36
|
+
$stderr.puts "WARNING: can't load #{lib}. Install it with: sudo gem install #{gem_name}"
|
37
|
+
return false
|
38
|
+
end
|
39
|
+
yield
|
40
|
+
end
|
41
|
+
|
42
|
+
after_requiring "jeweler" do
|
43
|
+
|
44
|
+
Jeweler::Tasks.new do |g|
|
45
|
+
g.name = "sham_rack"
|
46
|
+
g.version = ShamRack::VERSION
|
47
|
+
g.summary = "Net::HTTP-to-Rack plumbing"
|
48
|
+
g.email = "mdub@dogbiscuit.org"
|
49
|
+
g.homepage = "http://github.com/mdub/sham_rack"
|
50
|
+
g.description = "ShamRack plumbs Net::HTTP directly into Rack, for quick and easy HTTP testing."
|
51
|
+
g.authors = ["Mike Williams"]
|
52
|
+
g.rubyforge_project = "shamrack"
|
53
|
+
end
|
54
|
+
|
55
|
+
Jeweler::GemcutterTasks.new
|
56
|
+
# Jeweler::RubyforgeTasks.new
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
dir = Pathname(__FILE__).parent
|
5
|
+
$LOAD_PATH.unshift(dir.parent + "lib")
|
6
|
+
|
7
|
+
require dir + "hello_app"
|
8
|
+
require "sham_rack"
|
9
|
+
require "restclient"
|
10
|
+
|
11
|
+
# mount an instance of the app using ShamRack
|
12
|
+
ShamRack.mount(HelloApp.new, "hello.sham")
|
13
|
+
|
14
|
+
# run another instance in a separate process
|
15
|
+
server_pid = fork do
|
16
|
+
puts "Starting HTTP server on port 3333"
|
17
|
+
$stdout = File.new('/dev/null', 'w')
|
18
|
+
HelloApp.run!(:port => 3333)
|
19
|
+
end
|
20
|
+
|
21
|
+
at_exit do
|
22
|
+
puts "Killing HTTP server"
|
23
|
+
Process.kill("TERM", server_pid)
|
24
|
+
Process.wait(server_pid)
|
25
|
+
end
|
26
|
+
|
27
|
+
puts "Waiting for server to come up"
|
28
|
+
begin
|
29
|
+
puts RestClient.get("http://localhost:3333/hello/stranger")
|
30
|
+
rescue SystemCallError => e
|
31
|
+
retry
|
32
|
+
end
|
33
|
+
|
34
|
+
iterations = (ARGV.shift || 1000).to_i
|
35
|
+
|
36
|
+
%w(hello.sham localhost:3333).each do |site|
|
37
|
+
|
38
|
+
start = Time.now
|
39
|
+
|
40
|
+
iterations.times do
|
41
|
+
x = RestClient.get("http://#{site}/hello/stranger").to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
elapsed_time = (Time.now - start)
|
45
|
+
requests_per_second = iterations / elapsed_time.to_f
|
46
|
+
|
47
|
+
printf "%-20s #{iterations} requests in %f; %f per second\n", site, elapsed_time, requests_per_second
|
48
|
+
|
49
|
+
end
|
data/lib/sham_rack.rb
CHANGED
@@ -2,16 +2,19 @@ require "net/http"
|
|
2
2
|
require "sham_rack/registry"
|
3
3
|
require "sham_rack/http"
|
4
4
|
|
5
|
-
|
5
|
+
class << Net::HTTP
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
alias :new_without_sham_rack :new
|
8
|
+
|
9
|
+
def new(address, port = nil, *proxy_args)
|
10
|
+
port ||= Net::HTTP.default_port
|
9
11
|
rack_app = ShamRack.application_for(address, port)
|
12
|
+
http_object = new_without_sham_rack(address, port, *proxy_args)
|
10
13
|
if rack_app
|
11
|
-
ShamRack::HTTP
|
12
|
-
|
13
|
-
super(address, port, *proxy_args)
|
14
|
+
http_object.extend(ShamRack::HTTP::Extensions)
|
15
|
+
http_object.rack_app = rack_app
|
14
16
|
end
|
17
|
+
http_object
|
15
18
|
end
|
16
19
|
|
17
|
-
end
|
20
|
+
end
|
data/lib/sham_rack/http.rb
CHANGED
@@ -1,120 +1,101 @@
|
|
1
1
|
module ShamRack
|
2
|
-
|
3
|
-
# a sham version of Net::HTTP
|
4
|
-
class HTTP
|
5
|
-
|
6
|
-
def initialize(address, port, rack_app)
|
7
|
-
@address = address
|
8
|
-
@port = port
|
9
|
-
@rack_app = rack_app
|
10
|
-
end
|
11
2
|
|
12
|
-
|
13
|
-
|
14
|
-
attr_accessor :read_timeout, :open_timeout
|
15
|
-
attr_accessor :use_ssl,:key, :cert, :ca_file, :ca_path, :verify_mode, :verify_callback, :verify_depth, :cert_store
|
3
|
+
module HTTP
|
16
4
|
|
17
|
-
|
18
|
-
yield self
|
19
|
-
end
|
5
|
+
module Extensions
|
20
6
|
|
21
|
-
|
22
|
-
env = default_env
|
23
|
-
env.merge!(path_env(req.path))
|
24
|
-
env.merge!(method_env(req))
|
25
|
-
env.merge!(header_env(req))
|
26
|
-
env.merge!(io_env(req, body))
|
27
|
-
response = build_response(@rack_app.call(env))
|
28
|
-
yield response if block_given?
|
29
|
-
return response
|
30
|
-
end
|
31
|
-
|
32
|
-
def request_get(path, initheader = nil, &block)
|
33
|
-
request Net::HTTP::Get.new(path, initheader), &block
|
34
|
-
end
|
7
|
+
attr_accessor :rack_app
|
35
8
|
|
36
|
-
|
37
|
-
|
38
|
-
end
|
9
|
+
attr_accessor :read_timeout, :open_timeout
|
10
|
+
attr_accessor :use_ssl,:key, :cert, :ca_file, :ca_path, :verify_mode, :verify_callback, :verify_depth, :cert_store
|
39
11
|
|
40
|
-
|
41
|
-
|
42
|
-
|
12
|
+
def start
|
13
|
+
yield self
|
14
|
+
end
|
43
15
|
|
44
|
-
|
45
|
-
|
46
|
-
|
16
|
+
def request(req, body = nil)
|
17
|
+
env = default_env
|
18
|
+
env.merge!(path_env(req.path))
|
19
|
+
env.merge!(method_env(req))
|
20
|
+
env.merge!(header_env(req))
|
21
|
+
env.merge!(io_env(req, body))
|
22
|
+
response = build_response(@rack_app.call(env))
|
23
|
+
yield response if block_given?
|
24
|
+
return response
|
25
|
+
end
|
47
26
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
def method_env(request)
|
64
|
-
{
|
65
|
-
"REQUEST_METHOD" => request.method
|
66
|
-
}
|
67
|
-
end
|
68
|
-
|
69
|
-
def io_env(request, body)
|
70
|
-
raise(ArgumentError, "both request.body and body argument were provided") if (request.body && body)
|
71
|
-
body ||= request.body || ""
|
72
|
-
{
|
73
|
-
"rack.input" => StringIO.new(body),
|
74
|
-
"rack.errors" => $stderr
|
75
|
-
}
|
76
|
-
end
|
77
|
-
|
78
|
-
def path_env(path)
|
79
|
-
uri = URI.parse(path)
|
80
|
-
{
|
81
|
-
"PATH_INFO" => uri.path,
|
82
|
-
"QUERY_STRING" => (uri.query || ""),
|
83
|
-
}
|
84
|
-
end
|
85
|
-
|
86
|
-
def header_env(request)
|
87
|
-
result = {}
|
88
|
-
request.each do |header, content|
|
89
|
-
result["HTTP_" + header.upcase.gsub('-', '_')] = content
|
27
|
+
private
|
28
|
+
|
29
|
+
def default_env
|
30
|
+
{
|
31
|
+
"SCRIPT_NAME" => "",
|
32
|
+
"SERVER_NAME" => @address,
|
33
|
+
"SERVER_PORT" => @port.to_s,
|
34
|
+
"rack.version" => [0,1],
|
35
|
+
"rack.url_scheme" => "http",
|
36
|
+
"rack.multithread" => true,
|
37
|
+
"rack.multiprocess" => true,
|
38
|
+
"rack.run_once" => false
|
39
|
+
}
|
90
40
|
end
|
91
|
-
|
92
|
-
|
41
|
+
|
42
|
+
def method_env(request)
|
43
|
+
{
|
44
|
+
"REQUEST_METHOD" => request.method
|
45
|
+
}
|
93
46
|
end
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
47
|
+
|
48
|
+
def io_env(request, body)
|
49
|
+
raise(ArgumentError, "both request.body and body argument were provided") if (request.body && body)
|
50
|
+
body ||= request.body || ""
|
51
|
+
{
|
52
|
+
"rack.input" => StringIO.new(body),
|
53
|
+
"rack.errors" => $stderr
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def path_env(path)
|
58
|
+
uri = URI.parse(path)
|
59
|
+
{
|
60
|
+
"PATH_INFO" => uri.path,
|
61
|
+
"QUERY_STRING" => (uri.query || ""),
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def header_env(request)
|
66
|
+
result = {}
|
67
|
+
request.each do |header, content|
|
68
|
+
result["HTTP_" + header.upcase.gsub('-', '_')] = content
|
69
|
+
end
|
70
|
+
%w(TYPE LENGTH).each do |x|
|
71
|
+
result["CONTENT_#{x}"] = result.delete("HTTP_CONTENT_#{x}") if result.has_key?("HTTP_CONTENT_#{x}")
|
72
|
+
end
|
73
|
+
return result
|
74
|
+
end
|
75
|
+
|
76
|
+
def build_response(rack_response)
|
77
|
+
status, headers, body = rack_response
|
78
|
+
code, message = status.to_s.split(" ", 2)
|
79
|
+
response = Net::HTTPResponse.send(:response_class, code).new("Sham", code, message)
|
80
|
+
response.instance_variable_set(:@body, assemble_body(body))
|
81
|
+
response.instance_variable_set(:@read, true)
|
82
|
+
headers.each do |k,v|
|
83
|
+
response.add_field(k, v)
|
84
|
+
end
|
85
|
+
response.extend ShamRack::ResponseExtensions
|
86
|
+
return response
|
87
|
+
end
|
88
|
+
|
89
|
+
def assemble_body(body)
|
90
|
+
content = ""
|
91
|
+
body.each { |fragment| content << fragment }
|
92
|
+
return content
|
105
93
|
end
|
106
|
-
response.extend ShamRack::ResponseExtensions
|
107
|
-
return response
|
108
|
-
end
|
109
94
|
|
110
|
-
def assemble_body(body)
|
111
|
-
content = ""
|
112
|
-
body.each { |fragment| content << fragment }
|
113
|
-
return content
|
114
95
|
end
|
115
|
-
|
96
|
+
|
116
97
|
end
|
117
|
-
|
98
|
+
|
118
99
|
module ResponseExtensions
|
119
100
|
|
120
101
|
def read_body(dest = nil)
|
@@ -122,7 +103,7 @@ module ShamRack
|
|
122
103
|
dest << @body if dest
|
123
104
|
return @body
|
124
105
|
end
|
125
|
-
|
106
|
+
|
126
107
|
end
|
127
108
|
|
128
109
|
end
|
data/sham_rack.gemspec
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
1
4
|
# -*- encoding: utf-8 -*-
|
2
5
|
|
3
6
|
Gem::Specification.new do |s|
|
4
7
|
s.name = %q{sham_rack}
|
5
|
-
s.version = "1.
|
8
|
+
s.version = "1.2.0"
|
6
9
|
|
7
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
11
|
s.authors = ["Mike Williams"]
|
9
|
-
s.date = %q{2009-
|
12
|
+
s.date = %q{2009-11-27}
|
10
13
|
s.description = %q{ShamRack plumbs Net::HTTP directly into Rack, for quick and easy HTTP testing.}
|
11
14
|
s.email = %q{mdub@dogbiscuit.org}
|
12
15
|
s.extra_rdoc_files = [
|
@@ -17,21 +20,22 @@ Gem::Specification.new do |s|
|
|
17
20
|
"CHANGES.markdown",
|
18
21
|
"README.markdown",
|
19
22
|
"Rakefile",
|
20
|
-
"
|
23
|
+
"benchmark/benchmark.rb",
|
24
|
+
"benchmark/hello_app.rb",
|
21
25
|
"lib/sham_rack.rb",
|
22
26
|
"lib/sham_rack/core_ext/net/http.rb",
|
23
27
|
"lib/sham_rack/http.rb",
|
24
28
|
"lib/sham_rack/registry.rb",
|
29
|
+
"lib/sham_rack/version.rb",
|
25
30
|
"sham_rack.gemspec",
|
26
31
|
"spec/sham_rack_spec.rb",
|
27
32
|
"spec/spec_helper.rb"
|
28
33
|
]
|
29
|
-
s.has_rdoc = true
|
30
34
|
s.homepage = %q{http://github.com/mdub/sham_rack}
|
31
35
|
s.rdoc_options = ["--charset=UTF-8"]
|
32
36
|
s.require_paths = ["lib"]
|
33
37
|
s.rubyforge_project = %q{shamrack}
|
34
|
-
s.rubygems_version = %q{1.3.
|
38
|
+
s.rubygems_version = %q{1.3.5}
|
35
39
|
s.summary = %q{Net::HTTP-to-Rack plumbing}
|
36
40
|
s.test_files = [
|
37
41
|
"spec/sham_rack_spec.rb",
|
@@ -48,3 +52,4 @@ Gem::Specification.new do |s|
|
|
48
52
|
else
|
49
53
|
end
|
50
54
|
end
|
55
|
+
|
data/spec/sham_rack_spec.rb
CHANGED
@@ -238,6 +238,17 @@ describe ShamRack do
|
|
238
238
|
|
239
239
|
end
|
240
240
|
|
241
|
+
it "supports POST using Net::HTTP" do
|
242
|
+
|
243
|
+
Net::HTTP.start("env.xyz") do |http|
|
244
|
+
http.post("/resource", "q=rack")
|
245
|
+
end
|
246
|
+
|
247
|
+
env["REQUEST_METHOD"].should == "POST"
|
248
|
+
env["rack.input"].read.should == "q=rack"
|
249
|
+
|
250
|
+
end
|
251
|
+
|
241
252
|
it "supports PUT" do
|
242
253
|
|
243
254
|
RestClient.put("http://env.xyz/thing1", "stuff", :content_type => "text/plain")
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sham_rack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Williams
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-11-27 00:00:00 +11:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -26,11 +26,13 @@ files:
|
|
26
26
|
- CHANGES.markdown
|
27
27
|
- README.markdown
|
28
28
|
- Rakefile
|
29
|
-
-
|
29
|
+
- benchmark/benchmark.rb
|
30
|
+
- benchmark/hello_app.rb
|
30
31
|
- lib/sham_rack.rb
|
31
32
|
- lib/sham_rack/core_ext/net/http.rb
|
32
33
|
- lib/sham_rack/http.rb
|
33
34
|
- lib/sham_rack/registry.rb
|
35
|
+
- lib/sham_rack/version.rb
|
34
36
|
- sham_rack.gemspec
|
35
37
|
- spec/sham_rack_spec.rb
|
36
38
|
- spec/spec_helper.rb
|
@@ -58,7 +60,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
60
|
requirements: []
|
59
61
|
|
60
62
|
rubyforge_project: shamrack
|
61
|
-
rubygems_version: 1.3.
|
63
|
+
rubygems_version: 1.3.5
|
62
64
|
signing_key:
|
63
65
|
specification_version: 3
|
64
66
|
summary: Net::HTTP-to-Rack plumbing
|
data/VERSION.yml
DELETED