sham_rack 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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