resourceful 0.3.1 → 0.5.0

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