resourceful 0.3.1 → 0.5.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.
Files changed (38) hide show
  1. data/Manifest +24 -28
  2. data/Rakefile +44 -14
  3. data/lib/resourceful.rb +11 -21
  4. data/lib/resourceful/authentication_manager.rb +3 -2
  5. data/lib/resourceful/cache_manager.rb +58 -1
  6. data/lib/resourceful/exceptions.rb +34 -0
  7. data/lib/resourceful/header.rb +95 -0
  8. data/lib/resourceful/http_accessor.rb +0 -2
  9. data/lib/resourceful/memcache_cache_manager.rb +3 -13
  10. data/lib/resourceful/net_http_adapter.rb +15 -5
  11. data/lib/resourceful/request.rb +180 -18
  12. data/lib/resourceful/resource.rb +38 -141
  13. data/lib/resourceful/response.rb +142 -95
  14. data/resourceful.gemspec +9 -7
  15. data/spec/acceptance/authorization_spec.rb +16 -0
  16. data/spec/acceptance/caching_spec.rb +192 -0
  17. data/spec/acceptance/header_spec.rb +24 -0
  18. data/spec/acceptance/redirecting_spec.rb +12 -0
  19. data/spec/acceptance/resource_spec.rb +84 -0
  20. data/spec/acceptance_shared_specs.rb +12 -17
  21. data/spec/{acceptance_spec.rb → old_acceptance_specs.rb} +27 -57
  22. data/spec/simple_sinatra_server.rb +74 -0
  23. data/spec/simple_sinatra_server_spec.rb +98 -0
  24. data/spec/spec_helper.rb +21 -7
  25. metadata +50 -42
  26. data/spec/resourceful/authentication_manager_spec.rb +0 -249
  27. data/spec/resourceful/cache_manager_spec.rb +0 -223
  28. data/spec/resourceful/header_spec.rb +0 -38
  29. data/spec/resourceful/http_accessor_spec.rb +0 -164
  30. data/spec/resourceful/memcache_cache_manager_spec.rb +0 -111
  31. data/spec/resourceful/net_http_adapter_spec.rb +0 -96
  32. data/spec/resourceful/options_interpreter_spec.rb +0 -102
  33. data/spec/resourceful/request_spec.rb +0 -186
  34. data/spec/resourceful/resource_spec.rb +0 -600
  35. data/spec/resourceful/response_spec.rb +0 -238
  36. data/spec/resourceful/stubbed_resource_proxy_spec.rb +0 -58
  37. data/spec/simple_http_server_shared_spec.rb +0 -162
  38. data/spec/simple_http_server_shared_spec_spec.rb +0 -212
@@ -1,238 +0,0 @@
1
- require 'pathname'
2
- require Pathname(__FILE__).dirname + '../spec_helper'
3
-
4
- require 'resourceful/response'
5
-
6
- describe Resourceful::Response do
7
- before do
8
- @net_http = mock('net_http')
9
- Net::HTTP::Get.stub!(:new).and_return(@net_http)
10
- @uri = 'http://www.example.com'
11
-
12
- @response = Resourceful::Response.new(@uri, 0, {}, "")
13
- end
14
-
15
- describe 'init' do
16
-
17
- it 'should be instantiatable' do
18
- @response.should be_instance_of(Resourceful::Response)
19
- end
20
-
21
- it 'should take a [uri, code, header, body] array' do
22
- r = Resourceful::Response.new(@uri, 200, {}, "")
23
- r.code.should == 200
24
- r.header.should == {}
25
- r.body.should == ""
26
- end
27
-
28
- end
29
-
30
- it 'should have a code' do
31
- @response.should respond_to(:code)
32
- end
33
-
34
- it 'should have a header' do
35
- @response.should respond_to(:header)
36
- end
37
-
38
- it 'should have header aliased as headers' do
39
- @response.should respond_to(:headers)
40
- @response.headers.should == @response.header
41
- end
42
-
43
- describe "#is_success?" do
44
- it 'should be true for 200' do
45
- Resourceful::Response.new(@uri, 200, {}, "").is_success?.should == true
46
- end
47
-
48
- it 'should be true for any 2xx' do
49
- Resourceful::Response.new(@uri, 299, {}, "").is_success?.should == true
50
- end
51
-
52
- it 'should not be true for 300' do
53
- Resourceful::Response.new(@uri, 300, {}, "").is_success?.should == false
54
- end
55
-
56
- it 'should not be true for 199' do
57
- Resourceful::Response.new(@uri, 199, {}, "").is_success?.should == false
58
- end
59
- end
60
-
61
- describe '#is_unsuccesful?' do
62
- it 'should be true for a 4xx series response code' do
63
- Resourceful::Response.new(@uri, 404, {}, "").is_unsuccesful?.should == true
64
- end
65
-
66
- it 'should be true for a 5xx series response code' do
67
- Resourceful::Response.new(@uri, 500, {}, "").is_unsuccesful?.should == true
68
- end
69
-
70
- it 'should be not true for a 2xx series response code' do
71
- Resourceful::Response.new(@uri, 200, {}, "").is_unsuccesful?.should == false
72
- end
73
-
74
- it 'should be true for a 3xx series response code' do
75
- Resourceful::Response.new(@uri, 302, {}, "").is_unsuccesful?.should == true
76
- end
77
- end
78
-
79
- describe '#is_client_error?' do
80
- it 'be true for a 4xx series response code' do
81
- Resourceful::Response.new(@uri, 404, {}, "").is_client_error?.should == true
82
- end
83
-
84
- it 'be false for anything else' do
85
- Resourceful::Response.new(@uri, 200, {}, "").is_client_error?.should == false
86
- end
87
- end
88
-
89
- describe '#is_server_error?' do
90
- it 'be true for a 5xx series response code' do
91
- Resourceful::Response.new(@uri, 500, {}, "").is_server_error?.should == true
92
- end
93
-
94
- it 'be false for anything else' do
95
- Resourceful::Response.new(@uri, 200, {}, "").is_server_error?.should == false
96
- end
97
- end
98
-
99
-
100
- it 'should know if it is a redirect' do
101
- Resourceful::Response.new(@uri, 301, {}, "").is_redirect?.should == true
102
- Resourceful::Response.new(@uri, 302, {}, "").is_redirect?.should == true
103
- Resourceful::Response.new(@uri, 303, {}, "").is_redirect?.should == true
104
- Resourceful::Response.new(@uri, 307, {}, "").is_redirect?.should == true
105
-
106
- #aliased as was_redirect?
107
- Resourceful::Response.new(@uri, 301, {}, "").was_redirect?.should == true
108
- end
109
-
110
- it 'should know if it is a permanent redirect' do
111
- Resourceful::Response.new(@uri, 301, {}, "").is_permanent_redirect?.should == true
112
- end
113
-
114
- it 'should know if it is a temporary redirect' do
115
- Resourceful::Response.new(@uri, 303, {}, "").is_temporary_redirect?.should == true
116
- end
117
-
118
- it 'should know if its authoritative' do
119
- @response.should respond_to(:authoritative?)
120
- end
121
-
122
- it 'should allow authoritative to be set' do
123
- @response.authoritative = true
124
- @response.authoritative?.should be_true
125
- end
126
-
127
- it 'should know if it is authorized' do
128
- @response.should respond_to(:is_not_authorized?)
129
- Resourceful::Response.new(@uri, 200, {}, "").is_not_authorized?.should == false
130
- Resourceful::Response.new(@uri, 401, {}, "").is_not_authorized?.should == true
131
- end
132
-
133
- describe 'caching and expiration' do
134
- before do
135
- Time.stub!(:now).and_return(Time.utc(2008,5,15,18,0,1), Time.utc(2008,5,15,20,0,0))
136
-
137
- @response = Resourceful::Response.new(@uri, 0, {'Date' => ['Thu, 15 May 2008 18:00:00 GMT']}, "")
138
- @response.request_time = Time.utc(2008,5,15,17,59,59)
139
- end
140
-
141
- it 'should know if its #stale?' do
142
- @response.should respond_to(:stale?)
143
- end
144
-
145
- it 'should be stale if it is expired' do
146
- @response.should_receive(:expired?).and_return(true)
147
- @response.should be_stale
148
- end
149
-
150
- it 'should know if its #expired?' do
151
- @response.should respond_to(:expired?)
152
- end
153
-
154
- it 'should be expired if Now is after the "Expire" header' do
155
- Time.stub!(:now).and_return(Time.utc(2008,5,23,18,0))
156
- @response.header['Expire'] = [(Time.now - 60*60).httpdate]
157
-
158
- @response.should be_expired
159
- end
160
-
161
- it 'should have a #current_age' do
162
- @response.should respond_to(:current_age)
163
- end
164
-
165
- it 'should calculate the #current_age' do
166
- @response.current_age.should == (2 * 60 * 60 + 2)
167
- end
168
-
169
- it 'should know if its #cachable?' do
170
- @response.should respond_to(:cachable?)
171
- end
172
-
173
- it 'should normally be cachable' do
174
- @response.cachable?.should be_true
175
- end
176
-
177
- def response_with_header(header = {})
178
- Resourceful::Response.new(@uri, 200, header, "")
179
- end
180
-
181
- it 'should not be cachable if the vary header has "*"' do
182
- r = response_with_header('Vary' => ['*'])
183
- r.cachable?.should be_false
184
- end
185
-
186
- it 'should not be cachable if the Cache-Control header is set to no-store' do
187
- r = response_with_header('Cache-Control' => ['no-store'])
188
- r.cachable?.should be_false
189
- end
190
-
191
- it 'should be stale if the Cache-Control header is set to must-revalidate' do
192
- r = response_with_header('Cache-Control' => ['must-revalidate'])
193
- r.should be_stale
194
- end
195
-
196
- it 'should be stale if the Cache-Control header is set to no-cache' do
197
- r = response_with_header('Cache-Control' => ['no-cache'])
198
- r.should be_stale
199
- end
200
- end
201
-
202
-
203
- describe '#body' do
204
- it 'should have a body method' do
205
- @response.should respond_to(:body)
206
- end
207
-
208
- require 'zlib'
209
- ['gzip', ' gzip', ' gzip ', 'GZIP', 'gzIP'].each do |gzip|
210
- it "ungzip the body if content-encoding header field is #{gzip}" do
211
- compressed_date = StringIO.new.tap do |out|
212
- Zlib::GzipWriter.new(out).tap do |zout|
213
- zout << "This is a test"
214
- zout.close
215
- end
216
- end.string
217
-
218
- @response = Resourceful::Response.new(@uri, 0, {'Content-Encoding' => [gzip]}, compressed_date)
219
-
220
- @response.body.should == "This is a test"
221
- end
222
- end
223
-
224
- it 'should leave body unmolested if Content-Encoding missing' do
225
- @response = Resourceful::Response.new(@uri, 0, {}, "This is a test")
226
- @response.body.should == "This is a test"
227
- end
228
-
229
- it 'should raise error if Content-Encoding is not supported' do
230
- @response = Resourceful::Response.new(@uri, 0, {'Content-Encoding' => ['broken-identity']}, "This is a test")
231
- lambda {
232
- @response.body
233
- }.should raise_error(Resourceful::UnsupportedContentCoding)
234
- end
235
- end
236
-
237
- end
238
-
@@ -1,58 +0,0 @@
1
- require 'pathname'
2
- require Pathname(__FILE__).dirname + '../spec_helper'
3
-
4
- require 'resourceful/stubbed_resource_proxy'
5
-
6
- describe Resourceful::StubbedResourceProxy, "init" do
7
- it 'should require real resource' do
8
- lambda{
9
- Resourceful::StubbedResourceProxy.new
10
- }.should raise_error(ArgumentError)
11
- end
12
-
13
- it 'should require canned responses hash' do
14
- lambda{
15
- Resourceful::StubbedResourceProxy.new(stub('resource'))
16
- }.should raise_error(ArgumentError)
17
- end
18
-
19
- it 'should be creatable with a Resource and canned responses' do
20
- Resourceful::StubbedResourceProxy.new(stub('resource'), {})
21
- end
22
- end
23
-
24
- describe Resourceful::StubbedResourceProxy do
25
- before do
26
- @resource = stub('resource', :effective_uri => "http://test.invalid/foo")
27
- @stubbed_resource = Resourceful::StubbedResourceProxy.
28
- new(@resource, [{:mime_type => 'application/xml',
29
- :body => '<thing>1</thing>'}])
30
- end
31
-
32
- it 'should return canned response body for matching requests' do
33
- resp = @stubbed_resource.get
34
- resp.body.should == '<thing>1</thing>'
35
- resp['content-type'].should == 'application/xml'
36
- end
37
-
38
- it 'should pass #get() through to base resource if no matching canned response is defined' do
39
- @resource.should_receive(:get)
40
- @stubbed_resource.get(:accept => 'application/unknown')
41
- end
42
-
43
- it 'should pass #post() through to base resource if no canned response is defined' do
44
- @resource.should_receive(:post)
45
- @stubbed_resource.post
46
- end
47
-
48
- it 'should pass #put() through to base resource if no canned response is defined' do
49
- @resource.should_receive(:put)
50
- @stubbed_resource.put
51
- end
52
-
53
- it 'should pass #effective_uri() through to base resource if no canned response is defined' do
54
- @resource.should_receive(:effective_uri)
55
- @stubbed_resource.effective_uri
56
- end
57
-
58
- end
@@ -1,162 +0,0 @@
1
- require 'yaml'
2
-
3
- # this sets up a very simple http server using thin to be used in specs.
4
- SimpleGet = lambda do |env|
5
- body = ["Hello, world!"]
6
- [ 200, {'Content-Type' => 'text/plain', 'Content-Length' => body.join.size.to_s}, body ]
7
- end unless defined? SimpleGet
8
-
9
- SimplePost = lambda do |env|
10
- body = [env['rack.input'].string]
11
- [ 201, {'Content-Type' => 'text/plain', 'Content-Length' => body.join.size.to_s}, body ]
12
- end unless defined? SimplePost
13
-
14
- SimplePut = lambda do |env|
15
- body = [env['rack.input'].string]
16
- [ 200, {'Content-Type' => 'text/plain', 'Content-Length' => body.join.size.to_s}, body ]
17
- end unless defined? SimplePut
18
-
19
- SimpleDel = lambda do |env|
20
- body = ["KABOOM!"]
21
- [ 200, {'Content-Type' => 'text/plain', 'Content-Length' => body.join.size.to_s}, body ]
22
- end unless defined? SimpleDel
23
-
24
- # has the method used in the body of the response
25
- MethodResponder = lambda do |env|
26
- body = [env['REQUEST_METHOD']]
27
- [ 200, {'Content-Type' => 'text/plain', 'Content-Length' => body.join.size.to_s}, body ]
28
- end unless defined? MethodResponder
29
-
30
- # has a response code of whatever it was given in the url /code/{123}
31
- CodeResponder = lambda do |env|
32
- code = env['PATH_INFO'] =~ /([\d]+)/ ? Integer($1) : 404
33
- body = [code.to_s]
34
-
35
- [ code, {'Content-Type' => 'text/plain', 'Content-Length' => body.join.size.to_s}, body ]
36
- end unless defined? CodeResponder
37
-
38
- # YAML-parses the query string (expected hash) and sets the header to that
39
- HeaderResponder = lambda do |env|
40
- header = YAML.load(URI.unescape(env['QUERY_STRING']))
41
- body = [header.inspect]
42
-
43
- header.merge!({
44
- 'Content-Type' => 'text/plain',
45
- 'Content-Length' => body.join.size.to_s
46
- })
47
-
48
- [ 200, header, body ]
49
- end unless defined? HeaderResponder
50
-
51
- # Echos the request header in the response body
52
- EchoHeaderResponder = lambda do |env|
53
- body = [env.inspect]
54
-
55
- header = {
56
- 'Content-Type' => 'text/plain',
57
- 'Content-Length' => body.join.size.to_s
58
- }
59
-
60
- [ 200, header, body ]
61
- end unless defined? EchoHeaderResponder
62
-
63
- # redirect. /redirect/{301|302}?{url}
64
- Redirector = lambda do |env|
65
- code = env['PATH_INFO'] =~ /([\d]+)/ ? Integer($1) : 404
66
- location = env['QUERY_STRING']
67
- body = [location]
68
-
69
- [ code, {'Content-Type' => 'text/plain', 'Location' => location, 'Content-Length' => body.join.size.to_s}, body ]
70
- end unless defined? Redirector
71
-
72
- # Returns 304 if 'If-Modified-Since' is after given mod time
73
- ModifiedResponder = lambda do |env|
74
- modtime = Time.httpdate(URI.unescape(env['QUERY_STRING']))
75
-
76
- code = 200
77
- if env['HTTP_IF_MODIFIED_SINCE']
78
- code = 304
79
- end
80
- body = [modtime.to_s]
81
-
82
- header = {'Content-Type' => 'text/plain',
83
- 'Content-Length' => body.join.size.to_s,
84
- 'Last-Modified' => modtime.httpdate,
85
- 'Cache-Control' => 'must-revalidate'}
86
-
87
- [ code, header, body ]
88
- end unless defined? ModifiedResponder
89
-
90
- require 'rubygems'
91
- require 'httpauth'
92
- AuthorizationResponder = lambda do |env|
93
- authtype = env['QUERY_STRING']
94
- header = {}
95
- if auth_string = env['HTTP_AUTHORIZATION']
96
- if authtype == "basic" &&
97
- ['admin', 'secret'] == HTTPAuth::Basic.unpack_authorization(auth_string)
98
- code = 200
99
- body = ["Authorized"]
100
- elsif authtype == "digest" #&&
101
- credentials = HTTPAuth::Digest::Credentials.from_header(auth_string) &&
102
- credentials &&
103
- credentials.validate(:password => 'secret', :method => 'GET')
104
- code = 200
105
- body = ["Authorized"]
106
- else
107
- code = 401
108
- body = ["Not Authorized"]
109
- end
110
- else
111
- code = 401
112
- body = ["Not Authorized"]
113
- if authtype == "basic"
114
- header = {'WWW-Authenticate' => HTTPAuth::Basic.pack_challenge('Test Auth')}
115
- elsif authtype == "digest"
116
- chal = HTTPAuth::Digest::Credentials.new(:realm => 'Test Auth', :qop => 'auth')
117
- header = {'WWW-Authenticate' => chal.to_header}
118
- end
119
- end
120
-
121
- [ code, header.merge({'Content-Type' => 'text/plain', 'Content-Length' => body.join.size.to_s}), body ]
122
- end unless defined? AuthorizationResponder
123
-
124
- describe 'simple http server', :shared => true do
125
- before(:all) do
126
- require 'rack'
127
- require 'thin'
128
-
129
- app = Rack::Builder.new do |env|
130
- use Rack::ShowExceptions
131
-
132
- map( '/get' ){ run SimpleGet }
133
- map( '/post' ){ run SimplePost }
134
- map( '/put' ){ run SimplePut }
135
- map( '/delete' ){ run SimpleDel }
136
-
137
- map( '/method' ){ run MethodResponder }
138
- map( '/code' ){ run CodeResponder }
139
- map( '/redirect' ){ run Redirector }
140
- map( '/header' ){ run HeaderResponder }
141
- map( '/echo_header' ){ run EchoHeaderResponder }
142
- map( '/modified' ){ run ModifiedResponder }
143
- map( '/auth' ){ run AuthorizationResponder }
144
- end
145
-
146
- #spawn the server in a separate thread
147
- @httpd = Thread.new do
148
- Thin::Logging.silent = true
149
- # Thin::Logging.debug = true
150
- Thin::Server.start(app)
151
- end
152
- #give the server a chance to initialize
153
- sleep 0.05
154
- end
155
-
156
- after(:all) do
157
- # kill the server thread
158
- @httpd.exit
159
- end
160
-
161
-
162
- end