resourceful 0.2

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.
@@ -0,0 +1,90 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname + '../spec_helper'
3
+
4
+ require 'resourceful/net_http_adapter'
5
+
6
+ describe Resourceful::NetHttpAdapter do
7
+ describe '#make_request (mocked)' do
8
+ it 'should enable ssl on the connection' do
9
+ resp = stub('http_response', :code => 200, :header => {}, :body => "hello")
10
+ conn = stub('http_conn', :request => resp, :finish => nil)
11
+ Net::HTTP.should_receive(:new).and_return(conn)
12
+ conn.should_receive(:use_ssl=).with(true).ordered
13
+ conn.should_receive(:start).ordered
14
+
15
+ Resourceful::NetHttpAdapter.make_request(:get, 'https://localhost:3000/get')
16
+ end
17
+ end
18
+ end
19
+
20
+ describe Resourceful::NetHttpAdapter do
21
+ it_should_behave_like 'simple http server'
22
+
23
+
24
+ describe '#make_request' do
25
+ before do
26
+ @response = Resourceful::NetHttpAdapter.make_request(:get, 'http://localhost:3000/get')
27
+ end
28
+
29
+ describe 'response' do
30
+ it 'should be an array' do
31
+ @response.should be_instance_of(Array)
32
+ end
33
+
34
+ it 'should have the numeric response code as the first element' do
35
+ code = @response[0]
36
+ code.should be_instance_of(Fixnum)
37
+ code.should == 200
38
+ end
39
+
40
+ it 'should have the Header as the second element' do
41
+ header = @response[1]
42
+ header.should be_instance_of(Resourceful::Header)
43
+ header['content-type'].should == ['text/plain']
44
+ end
45
+
46
+ it 'should have the body as the third and last element' do
47
+ body = @response[2]
48
+ body.should == "Hello, world!"
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+
55
+ describe '#net_http_request_class' do
56
+
57
+ it 'should provide Net::HTTP::Get for a get method' do
58
+ Resourceful::NetHttpAdapter.send(:net_http_request_class, :get).should == Net::HTTP::Get
59
+ end
60
+
61
+ it 'should provide Net::HTTP::Post for a post method' do
62
+ Resourceful::NetHttpAdapter.send(:net_http_request_class, :post).should == Net::HTTP::Post
63
+ end
64
+
65
+ it 'should provide Net::HTTP::Put for a put method' do
66
+ Resourceful::NetHttpAdapter.send(:net_http_request_class, :put).should == Net::HTTP::Put
67
+ end
68
+
69
+ it 'should provide Net::HTTP::Delete for a delete method' do
70
+ Resourceful::NetHttpAdapter.send(:net_http_request_class, :delete).should == Net::HTTP::Delete
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+
77
+ describe Addressable::URI, '#absolute_path monkey patch' do
78
+
79
+ it 'should have the path and any query parameters' do
80
+ uri = Addressable::URI.parse('http://localhost/foo?bar=baz')
81
+ uri.absolute_path.should == '/foo?bar=baz'
82
+ end
83
+
84
+ it 'should not have a ? if there are no query params' do
85
+ uri = Addressable::URI.parse('http://localhost/foo')
86
+ uri.absolute_path.should_not =~ /\?/
87
+ uri.absolute_path.should == '/foo'
88
+ end
89
+
90
+ end
@@ -0,0 +1,94 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+ require 'resourceful/options_interpreter'
3
+
4
+ describe Resourceful::OptionsInterpreter, '#initialize' do
5
+ it 'should be creatable block' do
6
+ Resourceful::OptionsInterpreter.new() {}
7
+ end
8
+ end
9
+
10
+
11
+ describe Resourceful::OptionsInterpreter, "#option()" do
12
+ before do
13
+ @interpreter = Resourceful::OptionsInterpreter.new()
14
+ end
15
+
16
+ it 'should take option name' do
17
+ @interpreter.option(:test)
18
+ @interpreter.supported_options.should include(:test)
19
+ end
20
+
21
+ it 'should take interpretation block' do
22
+ @interpreter.option(:test) {"this"}
23
+ @interpreter.supported_options.should include(:test)
24
+ end
25
+ end
26
+
27
+ describe Resourceful::OptionsInterpreter, '#interpret(options)' do
28
+ before do
29
+ @interpreter = Resourceful::OptionsInterpreter.new()
30
+ @interpreter.option(:foo)
31
+ end
32
+
33
+ it 'should return hash like structure of interpreted options' do
34
+ opts = @interpreter.interpret(:foo => 'bar')
35
+
36
+ opts.should have_key(:foo)
37
+ opts[:foo].should == 'bar'
38
+ end
39
+
40
+ it 'should raise argument error if there is an unsupported option in src hash' do
41
+ lambda {
42
+ @interpreter.interpret(:bar => 'baz')
43
+ }.should raise_error(ArgumentError, "Unrecognized options: bar")
44
+ end
45
+
46
+ it 'should list all unsupported options in the exception' do
47
+ lambda {
48
+ @interpreter.interpret(:bar => 'baz', :baz => 'bar')
49
+ }.should raise_error(ArgumentError, /Unrecognized options: (bar, baz)|(baz, bar)/)
50
+ end
51
+
52
+ it 'should execute pass the options though the appropriate handling block' do
53
+ @interpreter.option(:foo) {|foo| foo + " hello"}
54
+
55
+ @interpreter.interpret(:foo => 'bar')[:foo].should == 'bar hello'
56
+ end
57
+
58
+ it 'should not include options that were not passed in resulting hash' do
59
+ @interpreter = Resourceful::OptionsInterpreter.new()
60
+ @interpreter.option(:foo)
61
+
62
+ @interpreter.interpret({}).keys.should_not include(:foo)
63
+ end
64
+
65
+ it 'should not invoked option value munging block if option is not specified'
66
+
67
+ it 'should use default if option is not specified' do
68
+ @interpreter = Resourceful::OptionsInterpreter.new()
69
+ @interpreter.option(:foo, :default => 'hello')
70
+
71
+ opts = @interpreter.interpret({})
72
+ opts.should have_key(:foo)
73
+ opts[:foo].should == 'hello'
74
+ end
75
+
76
+ it 'should use default value if option is specified as nil' do
77
+ @interpreter = Resourceful::OptionsInterpreter.new()
78
+ @interpreter.option(:foo, :default => 'hello')
79
+
80
+ opts = @interpreter.interpret({:foo => nil})
81
+ opts.should have_key(:foo)
82
+ opts[:foo].should == 'hello'
83
+ end
84
+
85
+ it 'should not use default if option is specified ' do
86
+ @interpreter = Resourceful::OptionsInterpreter.new()
87
+ @interpreter.option(:foo, :default => 'hello')
88
+
89
+ opts = @interpreter.interpret({:foo => 'bye'})
90
+ opts.should have_key(:foo)
91
+ opts[:foo].should == 'bye'
92
+ end
93
+
94
+ end
@@ -0,0 +1,261 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname + '../spec_helper'
3
+ require 'rubygems'
4
+ require 'addressable/uri'
5
+
6
+ describe Resourceful::Request do
7
+ before do
8
+ @uri = Addressable::URI.parse('http://www.example.com')
9
+ @resource = mock('resource')
10
+ @resource.stub!(:uri).and_return(@uri)
11
+
12
+ @request = Resourceful::Request.new(:get, @resource)
13
+
14
+ @cachemgr = mock('cache_mgr')
15
+ @cachemgr.stub!(:lookup).and_return(nil)
16
+ @cachemgr.stub!(:store)
17
+ @resource.stub!(:accessor).and_return(mock('accessor', :cache_manager => @cachemgr))
18
+ end
19
+
20
+ describe 'init' do
21
+
22
+ it 'should be instantiatable' do
23
+ @request.should be_instance_of(Resourceful::Request)
24
+ end
25
+
26
+ it 'should take an http method' do
27
+ @request.method.should == :get
28
+ end
29
+
30
+ it 'should take a resource' do
31
+ @request.resource.should == @resource
32
+ end
33
+
34
+ it 'should take an optional body' do
35
+ req = Resourceful::Request.new(:get, @resource)
36
+ req.body.should be_nil
37
+
38
+ req = Resourceful::Request.new(:post, @resource, 'Hello from post!')
39
+ req.body.should == 'Hello from post!'
40
+ end
41
+
42
+ it 'should have a request_time' do
43
+ @request.should respond_to(:request_time)
44
+ end
45
+
46
+ end
47
+
48
+ describe '#response' do
49
+ before do
50
+ @net_http_adapter_response = mock('net_http_adapter_response')
51
+ Resourceful::NetHttpAdapter.stub!(:make_request).and_return(@net_http_adapter_response)
52
+
53
+ @response = mock('response', :code => 200, :authoritative= => true)
54
+ Resourceful::Response.stub!(:new).and_return(@response)
55
+ end
56
+
57
+ it 'should be a method' do
58
+ @request.should respond_to(:response)
59
+ end
60
+
61
+ it 'should return the Response object' do
62
+ @request.response.should == @response
63
+ end
64
+
65
+ it 'should set the request_time to now' do
66
+ now = mock('now')
67
+ Time.stub!(:now).and_return(now)
68
+
69
+ @request.response
70
+ @request.request_time.should == now
71
+ end
72
+
73
+ describe 'Caching' do
74
+ before do
75
+ @cached_response = mock('cached_response', :body => "", :authoritative= => true)
76
+ @cached_response.stub!(:stale?).and_return(false)
77
+
78
+ @cached_response_header = mock('header', :[] => nil, :has_key? => false)
79
+ @cached_response.stub!(:header).and_return(@cached_response_header)
80
+
81
+ @cachemgr.stub!(:lookup).and_return(@cached_response)
82
+ end
83
+
84
+ it 'should lookup the request in the cache' do
85
+ @cachemgr.should_receive(:lookup).with(@request)
86
+ @request.response
87
+ end
88
+
89
+ it 'should check if the cached response is stale' do
90
+ @cached_response.should_receive(:stale?).and_return(false)
91
+ @request.response
92
+ end
93
+
94
+ describe 'cached' do
95
+
96
+ it 'should return the cached response if it was found and not stale' do
97
+ @cached_response.stale?.should_not be_true
98
+ @request.response.should == @cached_response
99
+ end
100
+
101
+ end
102
+
103
+ describe 'cached but stale' do
104
+ before do
105
+ @cached_response.stub!(:stale?).and_return(true)
106
+ end
107
+
108
+ it 'should add the validation headers from the cached_response to it\'s header' do
109
+ @request.should_receive(:set_validation_headers).with(@cached_response)
110
+
111
+ @request.response
112
+ end
113
+
114
+ it 'should #get the uri from the NetHttpAdapter' do
115
+ Resourceful::NetHttpAdapter.should_receive(:make_request).
116
+ with(:get, @uri, nil, anything).and_return(@net_http_adapter_response)
117
+ @request.response
118
+ end
119
+
120
+ it 'should create a Resourceful::Response object from the NetHttpAdapter response' do
121
+ Resourceful::Response.should_receive(:new).with(@request.uri, @net_http_adapter_response).and_return(@response)
122
+ @request.response
123
+ end
124
+
125
+ it 'should merge the response\'s headers with the cached response\'s if the response was a 304' do
126
+ @response_header = mock('header')
127
+ @response.stub!(:header).and_return(@response_header)
128
+ @response.stub!(:code).and_return(304)
129
+ @cached_response_header.should_receive(:merge).with(@response_header)
130
+ @request.response
131
+ end
132
+
133
+ it 'should store the response in the cache manager' do
134
+ @cachemgr.should_receive(:store).with(@request, @response)
135
+ @request.response
136
+ end
137
+
138
+ end
139
+
140
+ describe 'not cached' do
141
+ before do
142
+ @cachemgr.stub!(:lookup).and_return(nil)
143
+ end
144
+
145
+ it 'should #get the uri from the NetHttpAdapter' do
146
+ Resourceful::NetHttpAdapter.should_receive(:make_request).
147
+ with(:get, @uri, nil, anything).and_return(@net_http_adapter_response)
148
+ @request.response
149
+ end
150
+
151
+ it 'should create a Resourceful::Response object from the NetHttpAdapter response' do
152
+ Resourceful::Response.should_receive(:new).with(@request.uri, @net_http_adapter_response).and_return(@response)
153
+ @request.response
154
+ end
155
+
156
+ it 'should store the response in the cache manager' do
157
+ @cachemgr.should_receive(:store).with(@request, @response)
158
+ @request.response
159
+ end
160
+
161
+ end
162
+
163
+ describe '#set_validation_headers' do
164
+ it 'should have an #set_validation_headers method' do
165
+ @request.should respond_to(:set_validation_headers)
166
+ end
167
+
168
+ it 'should set If-None-Match to the cached response\'s ETag' do
169
+ @cached_response_header.should_receive(:[]).with('ETag').and_return('some etag')
170
+ @cached_response_header.should_receive(:has_key?).with('ETag').and_return(true)
171
+ @request.set_validation_headers(@cached_response)
172
+
173
+ @request.header['If-None-Match'].should == 'some etag'
174
+ end
175
+
176
+ it 'should not set If-None-Match if the cached response does not have an ETag' do
177
+ @request.set_validation_headers(@cached_response)
178
+ @request.header.should_not have_key('If-None-Match')
179
+ end
180
+
181
+ it 'should set If-Modified-Since to the cached response\'s Last-Modified' do
182
+ @cached_response_header.should_receive(:[]).with('Last-Modified').and_return('some date')
183
+ @cached_response_header.should_receive(:has_key?).with('Last-Modified').and_return(true)
184
+ @request.set_validation_headers(@cached_response)
185
+
186
+ @request.header['If-Modified-Since'].should == 'some date'
187
+ end
188
+
189
+ it 'should not set If-Modified-Since if the cached response does not have Last-Modified' do
190
+ @request.set_validation_headers(@cached_response)
191
+ @request.header.should_not have_key('If-Modified-Since')
192
+ end
193
+
194
+ it 'should add "Cache-Control: max-age=0" to the request when revalidating a response that has "Cache-Control: must-revalidate" set' do
195
+ @cached_response_header.should_receive(:[]).with('Cache-Control').and_return(['must-revalidate'])
196
+ @cached_response_header.should_receive(:has_key?).with('Cache-Control').and_return(true)
197
+ @request.set_validation_headers(@cached_response)
198
+
199
+ @request.header['Cache-Control'].should include('max-age=0')
200
+ end
201
+ end
202
+
203
+ end
204
+
205
+ end
206
+
207
+ describe '#should_be_redirected?' do
208
+ before do
209
+ @net_http_adapter_response = mock('net_http_adapter_response')
210
+ Resourceful::NetHttpAdapter.stub!(:make_request).and_return(@net_http_adapter_response)
211
+
212
+ @response = mock('response', :code => 200, :authoritative= => true)
213
+ Resourceful::Response.stub!(:new).and_return(@response)
214
+ end
215
+
216
+ describe 'with no callback set' do
217
+ before do
218
+ @callback = nil
219
+ @resource.stub!(:on_redirect).and_return(@callback)
220
+ end
221
+
222
+ it 'should be true for GET' do
223
+ request = Resourceful::Request.new(:get, @resource, @post_data)
224
+
225
+ request.should_be_redirected?.should be_true
226
+ end
227
+
228
+ it 'should be false for POST, etc' do
229
+ request = Resourceful::Request.new(:post, @resource, @post_data)
230
+
231
+ request.should_be_redirected?.should be_false
232
+ end
233
+
234
+ end
235
+
236
+ it 'should be true when callback returns true' do
237
+ @callback = lambda { true }
238
+ @resource.stub!(:on_redirect).and_return(@callback)
239
+ request = Resourceful::Request.new(:get, @resource, @post_data)
240
+
241
+ request.should_be_redirected?.should be_true
242
+ end
243
+
244
+ it 'should be false when callback returns false' do
245
+ @callback = lambda { false }
246
+ @resource.stub!(:on_redirect).and_return(@callback)
247
+ request = Resourceful::Request.new(:get, @resource, @post_data)
248
+
249
+ request.should_be_redirected?.should be_false
250
+ end
251
+
252
+ end
253
+
254
+ describe "content coding" do
255
+ it "should set Accept-Encoding automatically" do
256
+ @request.header['Accept-Encoding'].should == 'gzip, identity'
257
+ end
258
+ end
259
+
260
+ end
261
+
@@ -0,0 +1,481 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname + '../spec_helper'
3
+
4
+ require 'resourceful/resource'
5
+
6
+ describe Resourceful::Resource do
7
+ before do
8
+ @accessor = mock('http_accessor', :auth_manager => mock('authmgr', :add_credentials => nil))
9
+ @uri = 'http://www.example.com/'
10
+ @resource = Resourceful::Resource.new(@accessor, @uri)
11
+
12
+ @response = mock('response', :code => 200, :is_redirect? => false, :is_not_authorized? => false, :is_success? => true)
13
+
14
+ @request = mock('request', :response => @response, :should_be_redirected? => true)
15
+ Resourceful::Request.stub!(:new).and_return(@request)
16
+ end
17
+
18
+ describe 'init' do
19
+ it 'should be instantiatable' do
20
+ @resource.should be_instance_of(Resourceful::Resource)
21
+ end
22
+
23
+ it 'should take an http_accessor' do
24
+ @resource.accessor.should == @accessor
25
+ end
26
+
27
+ it 'should take a uri' do
28
+ @resource.uri.should == @uri
29
+ end
30
+ end
31
+
32
+ describe '#effective_uri' do
33
+
34
+ it 'should be the latest uri' do
35
+ @resource.effective_uri.should == @uri
36
+ end
37
+
38
+ it 'should be aliased as #uri' do
39
+ @resource.uri.should == @resource.effective_uri
40
+ end
41
+
42
+ end
43
+
44
+ describe '#do_read_request' do
45
+
46
+ def make_request
47
+ @resource.do_read_request(:some_method)
48
+ end
49
+
50
+ it 'should make a new request object from the method' do
51
+ Resourceful::Request.should_receive(:new).with(:some_method, @resource).and_return(@request)
52
+ make_request
53
+ end
54
+
55
+ describe 'non-success responses' do
56
+ before do
57
+ @uri = 'http://www.example.com/code/404'
58
+ @resource = Resourceful::Resource.new(@accessor, @uri)
59
+
60
+ @redirected_uri = 'http://www.example.com/get'
61
+ @redirect_response = mock('redirect_response',
62
+ :header => {'Location' => [@redirected_uri]},
63
+ :is_redirect? => false,
64
+ :is_success? => false,
65
+ :is_not_authorized? => false,
66
+ :code => 404)
67
+
68
+ @request.stub!(:response).and_return(@redirect_response, @response)
69
+ @request.stub!(:method).and_return(:get)
70
+ @request.stub!(:uri).and_return('http://www.example.com/code/404')
71
+ end
72
+
73
+ it 'should raise UnsuccessfulHttpRequestError' do
74
+ lambda {
75
+ @resource.do_read_request(:get)
76
+ }.should raise_error(Resourceful::UnsuccessfulHttpRequestError)
77
+ end
78
+
79
+ it 'should give a reasonable error message' do
80
+ lambda {
81
+ @resource.do_read_request(:get)
82
+ }.should raise_error("get request to <http://www.example.com/code/404> failed with code 404")
83
+ end
84
+ end
85
+
86
+ describe 'with redirection' do
87
+ before do
88
+ @uri = 'http://www.example.com/redirect/301?http://www.example.com/get'
89
+ @resource = Resourceful::Resource.new(@accessor, @uri)
90
+
91
+ @redirected_uri = 'http://www.example.com/get'
92
+ @redirect_response = mock('redirect_response',
93
+ :header => {'Location' => [@redirected_uri]},
94
+ :is_redirect? => true,
95
+ :is_permanent_redirect? => true)
96
+
97
+ @request.stub!(:response).and_return(@redirect_response, @response)
98
+
99
+ end
100
+
101
+ it 'should check if the response was a redirect' do
102
+ @redirect_response.should_receive(:is_redirect?).and_return(true)
103
+ make_request
104
+ end
105
+
106
+ it 'should check if the request should be redirected' do
107
+ @request.should_receive(:should_be_redirected?).and_return(true)
108
+ make_request
109
+ end
110
+
111
+ describe 'permanent redirect' do
112
+ before do
113
+ @redirect_response.stub!(:is_permanent_redirect?).and_return(true)
114
+ end
115
+
116
+ it 'should check if the response was a permanent redirect' do
117
+ @redirect_response.should_receive(:is_permanent_redirect?).and_return(true)
118
+ make_request
119
+ end
120
+
121
+ it 'should add the new location as the effective uri' do
122
+ make_request
123
+ @resource.effective_uri.should == @redirected_uri
124
+ end
125
+
126
+ it 'should remake the request with the new uri' do
127
+ Resourceful::Request.should_receive(:new).twice.and_return(@request)
128
+ @request.should_receive(:response).twice.and_return(@redirect_response, @response)
129
+ make_request
130
+ end
131
+
132
+ end
133
+
134
+ describe 'temporary redirect' do
135
+ before do
136
+ @redirect_response.stub!(:is_permanent_redirect?).and_return(false)
137
+ end
138
+
139
+ it 'should check if the response was not a permanent redirect' do
140
+ @redirect_response.should_receive(:is_permanent_redirect?).and_return(false)
141
+ make_request
142
+ end
143
+
144
+ it 'should not add the new location as the effective uri' do
145
+ make_request
146
+ @resource.effective_uri.should == @uri
147
+ end
148
+
149
+ it 'should make a new resource from the new location' do
150
+ new_resource = mock('resource', :do_read_request => @response)
151
+ Resourceful::Resource.should_receive(:new).with(@accessor, @redirected_uri).and_return(new_resource)
152
+ make_request
153
+ end
154
+
155
+ end
156
+
157
+ end # read with redirection
158
+
159
+ describe 'with authorization' do
160
+ before do
161
+ @authmgr = mock('auth_manager')
162
+ @authmgr.stub!(:add_credentials)
163
+ @authmgr.stub!(:associate_auth_info).and_return(true)
164
+
165
+ @accessor.stub!(:auth_manager).and_return(@authmgr)
166
+ end
167
+
168
+ it 'should attempt to add credentials to the request' do
169
+ @authmgr.should_receive(:add_credentials).with(@request)
170
+ make_request
171
+ end
172
+
173
+ it 'should check if the response was not authorized' do
174
+ @response.should_receive(:is_not_authorized?).and_return(false)
175
+ make_request
176
+ end
177
+
178
+ it 'should associate the auth info in the response if it was not authorized' do
179
+ @authmgr.should_receive(:associate_auth_info).with(@response).and_return(true)
180
+ @response.stub!(:is_not_authorized?).and_return(true)
181
+ make_request
182
+ end
183
+
184
+ it 'should re-make the request only once if it was not authorized the first time' do
185
+ Resourceful::Request.should_receive(:new).with(:some_method, @resource).twice.and_return(@request)
186
+ @response.stub!(:is_not_authorized?).and_return(true)
187
+ make_request
188
+ end
189
+
190
+ end
191
+
192
+ end
193
+
194
+ describe '#do_write_request' do
195
+
196
+ it 'should make a new request object from the method' do
197
+ Resourceful::Request.should_receive(:new).with(:some_method, @resource, "data", anything).and_return(@request)
198
+ @resource.do_write_request(:some_method, "data")
199
+ end
200
+
201
+ describe 'non-success responses' do
202
+ before do
203
+ @uri = 'http://www.example.com/code/404'
204
+ @resource = Resourceful::Resource.new(@accessor, @uri)
205
+
206
+ @redirected_uri = 'http://www.example.com/get'
207
+ @redirect_response = mock('redirect_response',
208
+ :header => {'Location' => [@redirected_uri]},
209
+ :is_redirect? => false,
210
+ :is_success? => false,
211
+ :is_not_authorized? => false,
212
+ :code => 404)
213
+
214
+ @request.stub!(:response).and_return(@redirect_response, @response)
215
+ @request.stub!(:method).and_return(:post)
216
+ @request.stub!(:uri).and_return('http://www.example.com/code/404')
217
+ end
218
+
219
+ it 'should raise UnsuccessfulHttpRequestError' do
220
+ lambda {
221
+ @resource.do_write_request(:post, "data", anything)
222
+ }.should raise_error(Resourceful::UnsuccessfulHttpRequestError)
223
+ end
224
+
225
+ it 'should give a reasonable error message' do
226
+ lambda {
227
+ @resource.do_write_request(:post, "data", anything)
228
+ }.should raise_error("post request to <http://www.example.com/code/404> failed with code 404")
229
+ end
230
+ end
231
+
232
+ describe 'with redirection' do
233
+ before do
234
+ @uri = 'http://www.example.com/redirect/301?http://www.example.com/get'
235
+ @resource = Resourceful::Resource.new(@accessor, @uri)
236
+
237
+ @redirected_uri = 'http://www.example.com/get'
238
+ @redirect_response = mock('redirect_response',
239
+ :header => {'Location' => [@redirected_uri]},
240
+ :is_redirect? => true,
241
+ :is_permanent_redirect? => true)
242
+
243
+ @request.stub!(:response).and_return(@redirect_response, @response)
244
+
245
+ end
246
+
247
+ def make_request
248
+ @resource.do_write_request(:some_method, "data", {})
249
+ end
250
+
251
+ it 'should check if the response was a redirect' do
252
+ @redirect_response.should_receive(:is_redirect?).and_return(true)
253
+ make_request
254
+ end
255
+
256
+ it 'should check if the request should be redirected' do
257
+ @request.should_receive(:should_be_redirected?).and_return(true)
258
+ make_request
259
+ end
260
+
261
+ describe 'permanent redirect' do
262
+ before do
263
+ @redirect_response.stub!(:is_permanent_redirect?).and_return(true)
264
+ end
265
+
266
+ it 'should check if the response was a permanent redirect' do
267
+ @redirect_response.should_receive(:is_permanent_redirect?).and_return(true)
268
+ make_request
269
+ end
270
+
271
+ it 'should add the new location as the effective uri' do
272
+ make_request
273
+ @resource.effective_uri.should == @redirected_uri
274
+ end
275
+
276
+ it 'should remake the request with the new uri' do
277
+ Resourceful::Request.should_receive(:new).twice.and_return(@request)
278
+ @request.should_receive(:response).twice.and_return(@redirect_response, @response)
279
+ make_request
280
+ end
281
+
282
+ end
283
+
284
+ describe 'temporary redirect' do
285
+ before do
286
+ @redirect_response.stub!(:is_permanent_redirect?).and_return(false)
287
+ @redirect_response.stub!(:code).and_return(302)
288
+ end
289
+
290
+ it 'should check if the response was not a permanent redirect' do
291
+ @redirect_response.should_receive(:is_permanent_redirect?).and_return(false)
292
+ make_request
293
+ end
294
+
295
+ it 'should not add the new location as the effective uri' do
296
+ make_request
297
+ @resource.effective_uri.should == @uri
298
+ end
299
+
300
+ it 'should make a new resource from the new location' do
301
+ new_resource = mock('resource', :do_write_request => @response)
302
+ Resourceful::Resource.should_receive(:new).with(@accessor, @redirected_uri).and_return(new_resource)
303
+ make_request
304
+ end
305
+
306
+ describe '302 Found' do
307
+ before do
308
+ @new_resource = mock('resource')
309
+ Resourceful::Resource.should_receive(:new).with(@accessor, @redirected_uri).and_return(@new_resource)
310
+ @redirect_response.stub!(:code).and_return(303)
311
+ end
312
+
313
+ it 'should redirect to the new location with a GET request, regardless of the original method' do
314
+ @new_resource.should_receive(:do_read_request).with(:get).and_return(@response)
315
+ make_request
316
+ end
317
+ end
318
+ end
319
+
320
+
321
+ end # write with redirection
322
+
323
+ end
324
+
325
+ describe 'callback registration' do
326
+ before do
327
+ @callback = mock('callback')
328
+ @callback.stub!(:call).and_return(true)
329
+
330
+ @resource.on_redirect { @callback.call }
331
+ end
332
+
333
+ it 'should store the callback when called with a block' do
334
+ @resource.on_redirect { true }
335
+
336
+ callback = @resource.instance_variable_get(:@on_redirect)
337
+ callback.should be_kind_of(Proc)
338
+ end
339
+
340
+ it 'should return the callback when called without a block' do
341
+ callback = lambda { "foo" }
342
+ @resource.on_redirect(&callback)
343
+ @resource.on_redirect.should == callback
344
+ end
345
+
346
+ end
347
+
348
+ describe '#get' do
349
+
350
+ it 'should be a method' do
351
+ @resource.should respond_to(:get)
352
+ end
353
+
354
+ it 'should pass :get to the #do_read_request method' do
355
+ @resource.should_receive(:do_read_request).with(:get)
356
+ @resource.get
357
+ end
358
+
359
+ it 'should return the response of making the request' do
360
+ @resource.get.should == @response
361
+ end
362
+
363
+ end
364
+
365
+ describe "#delete" do
366
+
367
+ it 'should be a method' do
368
+ @resource.should respond_to(:delete)
369
+ end
370
+
371
+ it 'should return the response of making the request' do
372
+ @resource.delete.should == @response
373
+ end
374
+
375
+ end
376
+
377
+ end
378
+
379
+ describe Resourceful::Resource do
380
+
381
+ describe "#post(body_data, :content_type => content-type)" do
382
+ before do
383
+ @auth_manager = mock('auth_manager', :add_credentials => nil)
384
+ @cache_manager = mock('cache_manager', :lookup => nil, :store => nil)
385
+ @accessor = mock('accessor', :auth_manager => @auth_manager, :cache_manager => @cache_manager)
386
+ @resource = Resourceful::Resource.new(@accessor, 'http://foo.invalid/')
387
+ @response = mock('response', :is_redirect? => false, :is_success? => true)
388
+ @request = mock('request', :response => @response)
389
+ Resourceful::Request.stub!(:new).and_return(@request)
390
+ end
391
+
392
+ it "should get the response from the request" do
393
+ @request.should_receive(:response).and_return(@response)
394
+
395
+ @resource.post("a body", :content_type => 'text/plain')
396
+ end
397
+
398
+ it 'should put the content type in the header' do
399
+ Resourceful::Request.should_receive(:new).
400
+ with(anything,anything, anything, hash_including('Content-Type' =>'text/plain')).
401
+ and_return(@request)
402
+
403
+ @resource.post("a body", :content_type => 'text/plain')
404
+ end
405
+
406
+ it 'should create a post request' do
407
+ Resourceful::Request.should_receive(:new).
408
+ with(:post, anything, anything, anything).
409
+ and_return(@request)
410
+
411
+ @resource.post("a body", :content_type => 'text/plain')
412
+ end
413
+
414
+ it 'should pass body to the request object' do
415
+ Resourceful::Request.should_receive(:new).
416
+ with(anything, anything, "a body", anything).
417
+ and_return(@request)
418
+
419
+ @resource.post("a body", :content_type => 'text/plain')
420
+ end
421
+
422
+ it 'should pass self to the request object' do
423
+ Resourceful::Request.should_receive(:new).
424
+ with(anything, @resource, anything, anything).
425
+ and_return(@request)
426
+
427
+ @resource.post("a body", :content_type => 'text/plain')
428
+ end
429
+ end
430
+
431
+ describe "#put(body_data, :content_type => content_type)" do
432
+ before do
433
+ @auth_manager = mock('auth_manager', :add_credentials => nil)
434
+ @cache_manager = mock('cache_manager', :lookup => nil, :store => nil)
435
+ @accessor = mock('accessor', :auth_manager => @auth_manager, :cache_manager => @cache_manager)
436
+ @resource = Resourceful::Resource.new(@accessor, 'http://foo.invalid/')
437
+ @response = mock('response', :is_redirect? => false, :is_success? => true)
438
+ @request = mock('request', :response => @response)
439
+ Resourceful::Request.stub!(:new).and_return(@request)
440
+ end
441
+
442
+ it "should get the response from the request" do
443
+ @request.should_receive(:response).and_return(@response)
444
+
445
+ @resource.put("a body", :content_type => 'text/plain')
446
+ end
447
+
448
+ it 'should put the content type in the header' do
449
+ Resourceful::Request.should_receive(:new).
450
+ with(anything,anything, anything, hash_including('Content-Type' =>'text/plain')).
451
+ and_return(@request)
452
+
453
+ @resource.put("a body", :content_type => 'text/plain')
454
+ end
455
+
456
+ it 'should create a put request' do
457
+ Resourceful::Request.should_receive(:new).
458
+ with(:put, anything, anything, anything).
459
+ and_return(@request)
460
+
461
+ @resource.put("a body", :content_type => 'text/plain')
462
+ end
463
+
464
+ it 'should pass body to the request object' do
465
+ Resourceful::Request.should_receive(:new).
466
+ with(anything, anything, "a body", anything).
467
+ and_return(@request)
468
+
469
+ @resource.put("a body", :content_type => 'text/plain')
470
+ end
471
+
472
+ it 'should pass self to the request object' do
473
+ Resourceful::Request.should_receive(:new).
474
+ with(anything, @resource, anything, anything).
475
+ and_return(@request)
476
+
477
+ @resource.put("a body", :content_type => 'text/plain')
478
+ end
479
+ end
480
+
481
+ end