sham_rack 1.3.2 → 1.3.3

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.
@@ -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