sham_rack 1.3.2 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,7 @@
1
+ ## 18-Oct-2010 [mdub@dogbiscuit.org]
2
+
3
+ * Add support for Patron.
4
+
1
5
  ## 02-Sep-2010 [mdub@dogbiscuit.org]
2
6
 
3
7
  * Fixes to support Ruby-1.9.x.
@@ -1,14 +1,14 @@
1
1
  ShamRack
2
2
  ========
3
3
 
4
- ShamRack plumbs Net:HTTP into [Rack][rack].
4
+ ShamRack plumbs HTTP requests into [Rack][rack].
5
5
 
6
6
  What's it for, again?
7
7
  ---------------------
8
8
 
9
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
- 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:
11
+ You can also use it to _test your Rack application_ (or Sinatra, or Rails, or Merb) using a variety of 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]
@@ -28,12 +28,12 @@ Using it
28
28
 
29
29
  require 'sham_rack'
30
30
 
31
- ShamRack.at("www.example.com") do |env|
31
+ ShamRack.at("www.greetings.com") do |env|
32
32
  ["200 OK", { "Content-type" => "text/plain" }, "Hello, world!"]
33
33
  end
34
34
 
35
35
  require 'open-uri'
36
- open("http://www.example.com/").read #=> "Hello, world!"
36
+ open("http://www.greetings.com/").read #=> "Hello, world!"
37
37
 
38
38
  ### Sinatra integration
39
39
 
@@ -67,6 +67,40 @@ Using it
67
67
 
68
68
  Or, just use Sinatra, as described above ... it's almost as succinct, and heaps more powerful.
69
69
 
70
+ ### When you're done testing
71
+
72
+ ShamRack.unmount_all
73
+
74
+ open("http://stubbed.com/greeting").read #=> OpenURI::HTTPError
75
+
76
+ Supported HTTP client libraries
77
+ -------------------------------
78
+
79
+ ### Net::HTTP and friends
80
+
81
+ ShamRack supports requests made using Net::HTTP, or any of the numerous APIs built on top of it:
82
+
83
+ uri = URI.parse("http://www.greetings.com/")
84
+ Net::HTTP.get_response(uri).body #=> "Hello, world!"
85
+
86
+ require 'open-uri'
87
+ open("http://www.greetings.com/").read #=> "Hello, world!"
88
+
89
+ require 'restclient'
90
+ RestClient.get("http://www.greetings.com/").to_s #=> "Hello, world!"
91
+
92
+ require 'mechanize'
93
+ Mechanize.new.get("http://www.greetings.com/").body #=> "Hello, world!"
94
+
95
+ ### Patron (experimental)
96
+
97
+ We've recently added support for [Patron][patron]:
98
+
99
+ require 'sham_rack/patron'
100
+
101
+ patron = Patron::Session.new
102
+ patron.get("http://www.greetings.com/").body #=> "Hello, world!"
103
+
70
104
  What's the catch?
71
105
  -----------------
72
106
 
@@ -85,3 +119,5 @@ Thanks to
85
119
  [httparty]: http://github.com/jnunemaker/httparty
86
120
  [oauth]: http://oauth.rubyforge.org/
87
121
  [fakeweb]: http://fakeweb.rubyforge.org/
122
+ [mechanize]: http://mechanize.rubyforge.org
123
+ [patron]: http://github.com/toland/Patron
data/Rakefile CHANGED
@@ -6,6 +6,10 @@ require "spec/rake/spectask"
6
6
  task "default" => "spec"
7
7
 
8
8
  Spec::Rake::SpecTask.new do |t|
9
- t.spec_opts = ["--colour", "--format", "progress"]
9
+ t.spec_opts = ["--colour", "--format", "nested"]
10
10
  t.spec_files = FileList['spec/**/*_spec.rb']
11
11
  end
12
+
13
+ require 'bundler'
14
+
15
+ Bundler::GemHelper.install_tasks
@@ -33,66 +33,41 @@ module ShamRack
33
33
  end
34
34
  end
35
35
 
36
- def request(req, body = nil)
37
- env = default_env
38
- env.merge!(path_env(req.path))
39
- env.merge!(method_env(req))
40
- env.merge!(header_env(req))
41
- env.merge!(io_env(req, body))
42
- response = build_response(@rack_app.call(env))
43
- yield response if block_given?
44
- return response
36
+ def request(request, body = nil)
37
+ rack_response = @rack_app.call(rack_env(request, body))
38
+ net_http_response = build_response(rack_response)
39
+ yield net_http_response if block_given?
40
+ return net_http_response
45
41
  end
46
42
 
47
43
  private
48
44
 
49
- def default_env
50
- {
51
- "SCRIPT_NAME" => "",
52
- "SERVER_NAME" => @address,
53
- "SERVER_PORT" => @port.to_s,
54
- "rack.version" => [0,1],
55
- "rack.url_scheme" => "http",
56
- "rack.multithread" => true,
57
- "rack.multiprocess" => true,
58
- "rack.run_once" => false
59
- }
45
+ def rack_env(request, body)
46
+ rack_env = request_env(request, body)
47
+ rack_env.merge!(header_env(request))
48
+ rack_env.merge!(server_env)
60
49
  end
61
-
62
- def method_env(request)
50
+
51
+ def server_env
63
52
  {
64
- "REQUEST_METHOD" => request.method
53
+ "SERVER_NAME" => @address,
54
+ "SERVER_PORT" => @port.to_s
65
55
  }
66
56
  end
67
-
68
- def io_env(request, body)
69
- raise(ArgumentError, "both request.body and body argument were provided") if (request.body && body)
70
- body ||= request.body || ""
71
- body = body.to_s
72
- body = body.encode("ASCII-8BIT") if body.respond_to?(:encode)
73
- {
74
- "rack.input" => StringIO.new(body),
75
- "rack.errors" => $stderr
76
- }
77
- end
78
-
79
- def path_env(path)
80
- uri = URI.parse(path)
81
- {
82
- "PATH_INFO" => uri.path,
83
- "QUERY_STRING" => (uri.query || ""),
84
- }
85
- end
86
-
57
+
87
58
  def header_env(request)
88
- result = {}
89
- request.each do |header, content|
90
- result["HTTP_" + header.upcase.gsub('-', '_')] = content
59
+ env = {}
60
+ request.each_header do |header, content|
61
+ key = header.upcase.gsub('-', '_')
62
+ key = "HTTP_" + key unless key =~ /^CONTENT_(TYPE|LENGTH)$/
63
+ env[key] = content
91
64
  end
92
- %w(TYPE LENGTH).each do |x|
93
- result["CONTENT_#{x}"] = result.delete("HTTP_CONTENT_#{x}") if result.has_key?("HTTP_CONTENT_#{x}")
94
- end
95
- return result
65
+ env
66
+ end
67
+
68
+ def request_env(request, body)
69
+ body ||= request.body || ""
70
+ Rack::MockRequest.env_for(request.path, :method => request.method, :input => body.to_s)
96
71
  end
97
72
 
98
73
  def build_response(rack_response)
@@ -111,7 +86,7 @@ module ShamRack
111
86
  def assemble_body(body)
112
87
  content = ""
113
88
  body.each { |fragment| content << fragment }
114
- return content
89
+ content
115
90
  end
116
91
 
117
92
  end
@@ -0,0 +1,64 @@
1
+ require "patron"
2
+ require "sham_rack/registry"
3
+ require "uri"
4
+
5
+ module Patron
6
+
7
+ class Session
8
+
9
+ alias :handle_request_without_sham_rack :handle_request
10
+
11
+ def handle_request(patron_request)
12
+ uri = URI.parse(patron_request.url)
13
+ rack_app = ShamRack.application_for(uri.host, uri.port)
14
+ if rack_app
15
+ handle_request_with_rack(patron_request, rack_app)
16
+ else
17
+ handle_request_without_sham_rack(patron_request)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def handle_request_with_rack(patron_request, rack_app)
24
+ env = rack_env_for(patron_request)
25
+ rack_response = rack_app.call(env)
26
+ patron_response(rack_response)
27
+ end
28
+
29
+ def rack_env_for(patron_request)
30
+ env = Rack::MockRequest.env_for(patron_request.url, :method => patron_request.action, :input => patron_request.upload_data)
31
+ env.merge!(header_env(patron_request))
32
+ env
33
+ end
34
+
35
+ def patron_response(rack_response)
36
+ status, headers, body = rack_response
37
+ status_code = Rack::Utils::HTTP_STATUS_CODES[status.to_i]
38
+ res = Patron::Response.new
39
+ res.instance_variable_set(:@status, status)
40
+ res.instance_variable_set(:@status_line, "HTTP/1.1 #{status} #{status_code}")
41
+ res.instance_variable_set(:@body, assemble_body(body))
42
+ res.instance_variable_set(:@headers, headers)
43
+ res
44
+ end
45
+
46
+ def header_env(patron_request)
47
+ env = {}
48
+ patron_request.headers.each do |header, content|
49
+ key = header.upcase.gsub('-', '_')
50
+ key = "HTTP_" + key unless key =~ /^CONTENT_(TYPE|LENGTH)$/
51
+ env[key] = content
52
+ end
53
+ env
54
+ end
55
+
56
+ def assemble_body(body)
57
+ content = ""
58
+ body.each { |fragment| content << fragment }
59
+ content
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -1,3 +1,3 @@
1
1
  module ShamRack
2
- VERSION = "1.3.2"
2
+ VERSION = "1.3.3"
3
3
  end
@@ -1,62 +1,12 @@
1
1
  require "spec_helper"
2
2
 
3
3
  require "sham_rack"
4
+ require "sham_rack/patron"
4
5
  require "open-uri"
5
6
  require "restclient"
6
7
  require "mechanize"
7
8
  require "rack"
8
9
 
9
- class PlainTextApp
10
-
11
- def call(env)
12
- [
13
- "200 OK",
14
- { "Content-Type" => "text/plain", "Content-Length" => message.length.to_s },
15
- [message]
16
- ]
17
- end
18
-
19
- end
20
-
21
- class SimpleMessageApp < PlainTextApp
22
-
23
- def initialize(message)
24
- @message = message
25
- end
26
-
27
- attr_reader :message
28
-
29
- end
30
-
31
- class EnvRecordingApp < PlainTextApp
32
-
33
- def call(env)
34
- @last_env = env
35
- super
36
- end
37
-
38
- attr_reader :last_env
39
-
40
- def message
41
- "env stored for later perusal"
42
- end
43
-
44
- end
45
-
46
- class UpcaseBody
47
-
48
- def initialize(app)
49
- @app = app
50
- end
51
-
52
- def call(env)
53
- status, headers, body = @app.call(env)
54
- upcased_body = Array(body).map { |x| x.upcase }
55
- [status, headers, upcased_body]
56
- end
57
-
58
- end
59
-
60
10
  describe ShamRack do
61
11
 
62
12
  after(:each) do
@@ -66,71 +16,46 @@ describe ShamRack do
66
16
  describe "mounted Rack application" do
67
17
 
68
18
  before(:each) do
69
- ShamRack.mount(SimpleMessageApp.new("Hello, world"), "www.test.xyz")
19
+ ShamRack.mount(GreetingApp.new, "www.greetings.com")
70
20
  end
71
21
 
72
22
  it "can be accessed using Net::HTTP" do
73
- response = Net::HTTP.start("www.test.xyz") do |http|
23
+ response = Net::HTTP.start("www.greetings.com") do |http|
74
24
  http.request(Net::HTTP::Get.new("/"))
75
25
  end
76
26
  response.body.should == "Hello, world"
77
27
  end
78
28
 
79
29
  it "can be accessed using Net::HTTP#get_response" do
80
- response = Net::HTTP.get_response(URI.parse("http://www.test.xyz/"))
30
+ response = Net::HTTP.get_response(URI.parse("http://www.greetings.com/"))
81
31
  response.body.should == "Hello, world"
82
32
  end
83
33
 
84
34
  it "can be accessed using open-uri" do
85
- response = open("http://www.test.xyz")
35
+ response = open("http://www.greetings.com")
86
36
  response.status.should == ["200", "OK"]
87
37
  response.read.should == "Hello, world"
88
38
  end
89
39
 
90
40
  it "can be accessed using RestClient" do
91
- response = RestClient.get("http://www.test.xyz")
41
+ response = RestClient.get("http://www.greetings.com")
92
42
  response.code.should == 200
93
43
  response.to_s.should == "Hello, world"
94
44
  end
95
45
 
96
- it "can be accessed using WWW::Mechanize" do
97
- response = Mechanize.new.get("http://www.test.xyz")
46
+ it "can be accessed using Mechanize" do
47
+ response = Mechanize.new.get("http://www.greetings.com")
98
48
  response.body.should == "Hello, world"
99
49
  end
100
50
 
101
- end
102
-
103
- describe "response" do
104
-
105
- before(:each) do
106
- ShamRack.at("www.test.xyz") do
107
- [
108
- "201 Created",
109
- { "Content-Type" => "text/plain", "X-Foo" => "bar" },
110
- ["BODY"]
111
- ]
112
- end
113
- @response = Net::HTTP.get_response(URI.parse("http://www.test.xyz/"))
114
- end
115
-
116
- it "has status returned by app" do
117
- @response.code.should == "201"
51
+ it "can be accessed using Patron" do
52
+ patron = Patron::Session.new
53
+ response = patron.get("http://www.greetings.com/foo/bar")
54
+ response.body.should == "Hello, world"
118
55
  end
119
56
 
120
- it "has body returned by app" do
121
- @response.body.should == "BODY"
122
- end
123
-
124
- it "has Content-Type returned by app" do
125
- @response.content_type.should == "text/plain"
126
- end
127
-
128
- it "has other headers returned by app" do
129
- @response["x-foo"].should =="bar"
130
- end
131
-
132
57
  end
133
-
58
+
134
59
  describe ".at" do
135
60
 
136
61
  describe "with a block" do
@@ -152,12 +77,12 @@ describe ShamRack do
152
77
  before do
153
78
  @return_value = ShamRack.at("rackup.xyz").rackup do
154
79
  use UpcaseBody
155
- run SimpleMessageApp.new("Racked!")
80
+ run GreetingApp.new
156
81
  end
157
82
  end
158
83
 
159
84
  it "mounts an app created using Rack::Builder" do
160
- open("http://rackup.xyz").read.should == "RACKED!"
85
+ open("http://rackup.xyz").read.should == "HELLO, WORLD"
161
86
  end
162
87
 
163
88
  it "returns the app" do
@@ -204,10 +129,41 @@ describe ShamRack do
204
129
 
205
130
  end
206
131
 
132
+ describe "response" do
133
+
134
+ before(:each) do
135
+ ShamRack.at("www.greetings.com") do
136
+ [
137
+ "201 Created",
138
+ { "Content-Type" => "text/plain", "X-Foo" => "bar" },
139
+ ["BODY"]
140
+ ]
141
+ end
142
+ @response = Net::HTTP.get_response(URI.parse("http://www.greetings.com/"))
143
+ end
144
+
145
+ it "has status returned by app" do
146
+ @response.code.should == "201"
147
+ end
148
+
149
+ it "has body returned by app" do
150
+ @response.body.should == "BODY"
151
+ end
152
+
153
+ it "has Content-Type returned by app" do
154
+ @response.content_type.should == "text/plain"
155
+ end
156
+
157
+ it "has other headers returned by app" do
158
+ @response["x-foo"].should =="bar"
159
+ end
160
+
161
+ end
162
+
207
163
  describe "Rack environment" do
208
164
 
209
165
  before(:each) do
210
- @env_recorder = recorder = EnvRecordingApp.new
166
+ @env_recorder = recorder = EnvRecorder.new(GreetingApp.new)
211
167
  ShamRack.at("env.xyz").rackup do
212
168
  use Rack::Lint
213
169
  run recorder
@@ -229,7 +185,7 @@ describe ShamRack do
229
185
  env["SERVER_NAME"].should == "env.xyz"
230
186
  env["SERVER_PORT"].should == "80"
231
187
 
232
- env["rack.version"].should == [0,1]
188
+ env["rack.version"].should be_kind_of(Array)
233
189
  env["rack.url_scheme"].should == "http"
234
190
 
235
191
  env["rack.multithread"].should == true
@@ -271,6 +227,19 @@ describe ShamRack do
271
227
 
272
228
  end
273
229
 
230
+ it "supports POST using Patron" do
231
+
232
+ patron = Patron::Session.new
233
+ response = patron.post("http://env.xyz/resource", "<xml/>", "Content-Type" => "application/xml")
234
+
235
+ response.status.should == "200 OK"
236
+
237
+ env["REQUEST_METHOD"].should == "POST"
238
+ env["rack.input"].read.should == "<xml/>"
239
+ env["CONTENT_TYPE"].should == "application/xml"
240
+
241
+ end
242
+
274
243
  it "supports PUT" do
275
244
 
276
245
  RestClient.put("http://env.xyz/thing1", "stuff", :content_type => "text/plain")
@@ -281,6 +250,17 @@ describe ShamRack do
281
250
 
282
251
  end
283
252
 
253
+ it "supports PUT using Patron" do
254
+
255
+ patron = Patron::Session.new
256
+ response = patron.put("http://env.xyz/resource", "stuff", "Content-Type" => "text/plain")
257
+
258
+ env["REQUEST_METHOD"].should == "PUT"
259
+ env["CONTENT_TYPE"].should == "text/plain"
260
+ env["rack.input"].read.should == "stuff"
261
+
262
+ end
263
+
284
264
  it "supports DELETE" do
285
265
 
286
266
  RestClient.delete("http://env.xyz/thing/1")
@@ -290,6 +270,16 @@ describe ShamRack do
290
270
 
291
271
  end
292
272
 
273
+ it "supports DELETE using Patron" do
274
+
275
+ patron = Patron::Session.new
276
+ response = patron.delete("http://env.xyz/resource")
277
+
278
+ env["REQUEST_METHOD"].should == "DELETE"
279
+ env["PATH_INFO"].should == "/resource"
280
+
281
+ end
282
+
293
283
  end
294
284
 
295
285
  end
@@ -2,10 +2,8 @@ require "rubygems"
2
2
  require "spec"
3
3
  require "rr"
4
4
 
5
- project_root = File.expand_path("#{__FILE__}/../..")
6
- $LOAD_PATH << "#{project_root}/lib"
7
- $LOAD_PATH << "#{project_root}/spec/support/lib"
8
-
9
5
  Spec::Runner.configure do |config|
10
6
  config.mock_with RR::Adapters::Rspec
11
7
  end
8
+
9
+ require "test_apps"
@@ -0,0 +1,48 @@
1
+ require "rack"
2
+
3
+ class GreetingApp
4
+
5
+ include Rack::Utils
6
+
7
+ def call(env)
8
+ params = parse_nested_query(env["QUERY_STRING"])
9
+ salutation = params[:salutation] || "Hello"
10
+ subject = params[:subject] || "world"
11
+ message = "#{salutation}, #{subject}"
12
+ [
13
+ "200 OK",
14
+ { "Content-Type" => "text/plain", "Content-Length" => message.length.to_s },
15
+ [message]
16
+ ]
17
+ end
18
+
19
+ end
20
+
21
+ class EnvRecorder
22
+
23
+ def initialize(app)
24
+ @app = app
25
+ end
26
+
27
+ def call(env)
28
+ @last_env = env
29
+ @app.call(env)
30
+ end
31
+
32
+ attr_reader :last_env
33
+
34
+ end
35
+
36
+ class UpcaseBody
37
+
38
+ def initialize(app)
39
+ @app = app
40
+ end
41
+
42
+ def call(env)
43
+ status, headers, body = @app.call(env)
44
+ upcased_body = Array(body).map { |x| x.upcase }
45
+ [status, headers, upcased_body]
46
+ end
47
+
48
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sham_rack
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
4
+ hash: 29
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 3
9
- - 2
10
- version: 1.3.2
9
+ - 3
10
+ version: 1.3.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Mike Williams
@@ -15,10 +15,23 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-09-02 00:00:00 +10:00
18
+ date: 2010-12-22 00:00:00 +11:00
19
19
  default_executable:
20
- dependencies: []
21
-
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rack
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
22
35
  description: ShamRack plumbs Net::HTTP directly into Rack, for quick and easy HTTP testing.
23
36
  email: mdub@dogbiscuit.org
24
37
  executables: []
@@ -29,6 +42,7 @@ extra_rdoc_files: []
29
42
 
30
43
  files:
31
44
  - lib/sham_rack/net_http.rb
45
+ - lib/sham_rack/patron.rb
32
46
  - lib/sham_rack/registry.rb
33
47
  - lib/sham_rack/stub_web_service.rb
34
48
  - lib/sham_rack/version.rb
@@ -38,6 +52,7 @@ files:
38
52
  - spec/sham_rack/stub_web_service_spec.rb
39
53
  - spec/sham_rack_spec.rb
40
54
  - spec/spec_helper.rb
55
+ - spec/test_apps.rb
41
56
  - Rakefile
42
57
  - benchmark/benchmark.rb
43
58
  - benchmark/hello_app.rb
@@ -79,6 +94,7 @@ test_files:
79
94
  - spec/sham_rack/stub_web_service_spec.rb
80
95
  - spec/sham_rack_spec.rb
81
96
  - spec/spec_helper.rb
97
+ - spec/test_apps.rb
82
98
  - Rakefile
83
99
  - benchmark/benchmark.rb
84
100
  - benchmark/hello_app.rb