paul-resourceful 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/MIT-LICENSE +21 -0
  2. data/Manifest.txt +34 -0
  3. data/README.markdown +86 -0
  4. data/Rakefile +14 -0
  5. data/lib/resourceful.rb +29 -0
  6. data/lib/resourceful/authentication_manager.rb +107 -0
  7. data/lib/resourceful/cache_manager.rb +174 -0
  8. data/lib/resourceful/header.rb +31 -0
  9. data/lib/resourceful/http_accessor.rb +85 -0
  10. data/lib/resourceful/net_http_adapter.rb +60 -0
  11. data/lib/resourceful/options_interpreter.rb +78 -0
  12. data/lib/resourceful/request.rb +63 -0
  13. data/lib/resourceful/resource.rb +266 -0
  14. data/lib/resourceful/response.rb +175 -0
  15. data/lib/resourceful/stubbed_resource_proxy.rb +47 -0
  16. data/lib/resourceful/util.rb +6 -0
  17. data/lib/resourceful/version.rb +1 -0
  18. data/resourceful.gemspec +30 -0
  19. data/spec/acceptance_shared_specs.rb +49 -0
  20. data/spec/acceptance_spec.rb +408 -0
  21. data/spec/resourceful/authentication_manager_spec.rb +249 -0
  22. data/spec/resourceful/cache_manager_spec.rb +211 -0
  23. data/spec/resourceful/header_spec.rb +38 -0
  24. data/spec/resourceful/http_accessor_spec.rb +125 -0
  25. data/spec/resourceful/net_http_adapter_spec.rb +96 -0
  26. data/spec/resourceful/options_interpreter_spec.rb +94 -0
  27. data/spec/resourceful/request_spec.rb +186 -0
  28. data/spec/resourceful/resource_spec.rb +600 -0
  29. data/spec/resourceful/response_spec.rb +238 -0
  30. data/spec/resourceful/stubbed_resource_proxy_spec.rb +58 -0
  31. data/spec/simple_http_server_shared_spec.rb +160 -0
  32. data/spec/simple_http_server_shared_spec_spec.rb +212 -0
  33. data/spec/spec.opts +3 -0
  34. data/spec/spec_helper.rb +14 -0
  35. metadata +98 -0
@@ -0,0 +1,600 @@
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
+ @auth_manager = mock('auth_manager', :add_credentials => nil)
9
+ @cache_manager = mock('cache_manager', :lookup => nil, :store => nil, :invalidate => nil)
10
+ @logger = mock('logger', :debug => nil, :info => nil)
11
+ @accessor = mock('accessor', :auth_manager => @auth_manager,
12
+ :cache_manager => @cache_manager,
13
+ :logger => @logger)
14
+
15
+ @uri = 'http://www.example.com/'
16
+ @resource = Resourceful::Resource.new(@accessor, @uri)
17
+
18
+ @response = mock('response', :code => 200,
19
+ :is_redirect? => false,
20
+ :is_not_authorized? => false,
21
+ :is_success? => true,
22
+ :is_not_modified? => false)
23
+
24
+ @request = mock('request', :response => @response, :should_be_redirected? => true, :uri => @uri)
25
+ Resourceful::Request.stub!(:new).and_return(@request)
26
+ end
27
+
28
+ describe 'init' do
29
+ it 'should be instantiatable' do
30
+ @resource.should be_instance_of(Resourceful::Resource)
31
+ end
32
+
33
+ it 'should take an http_accessor' do
34
+ @resource.accessor.should == @accessor
35
+ end
36
+
37
+ it 'should take a uri' do
38
+ @resource.uri.should == @uri
39
+ end
40
+
41
+ it 'should take some default_options' do
42
+ r = Resourceful::Resource.new(@accessor, @uri, :foo => :bar)
43
+ r.default_options.should == {:foo => :bar}
44
+ end
45
+
46
+ it 'should default to an empty hash for options' do
47
+ @resource.default_options.should == {}
48
+ end
49
+ end
50
+
51
+ describe '#effective_uri' do
52
+
53
+ it 'should be the latest uri' do
54
+ @resource.effective_uri.should == @uri
55
+ end
56
+
57
+ it 'should be aliased as #uri' do
58
+ @resource.uri.should == @resource.effective_uri
59
+ end
60
+
61
+ end
62
+
63
+ describe '#do_read_request' do
64
+
65
+ def make_request
66
+ @resource.do_read_request(:some_method)
67
+ end
68
+
69
+ it 'should make a new request object from the method' do
70
+ Resourceful::Request.should_receive(:new).with(:some_method, @resource, nil, {}).and_return(@request)
71
+ make_request
72
+ end
73
+
74
+ it 'should set the header of the request from the header arg' do
75
+ Resourceful::Request.should_receive(:new).with(:some_method, @resource, nil, :foo => :bar).and_return(@request)
76
+ @resource.do_read_request(:some_method, :foo => :bar)
77
+ end
78
+
79
+ describe 'default options' do
80
+ before do
81
+ @resource.default_options = {:foo => :bar}
82
+ end
83
+
84
+ it 'should merge the header with the default options' do
85
+ Resourceful::Request.should_receive(:new).with(anything, anything, anything, :foo => :bar).and_return(@request)
86
+ make_request
87
+ end
88
+
89
+ it 'should override any default header with the request header' do
90
+ Resourceful::Request.should_receive(:new).with(anything, anything, anything, :foo => :baz).and_return(@request)
91
+ @resource.do_read_request(:some_method, :foo => :baz)
92
+ end
93
+ end
94
+
95
+ describe 'non-success responses' do
96
+ before do
97
+ @uri = 'http://www.example.com/code/404'
98
+ @resource = Resourceful::Resource.new(@accessor, @uri)
99
+
100
+ @redirected_uri = 'http://www.example.com/get'
101
+ @redirect_response = mock('redirect_response',
102
+ :header => {'Location' => [@redirected_uri]},
103
+ :is_redirect? => false,
104
+ :is_success? => false,
105
+ :is_not_authorized? => false,
106
+ :is_not_modified? => false,
107
+ :code => 404)
108
+
109
+ @request.stub!(:response).and_return(@redirect_response, @response)
110
+ @request.stub!(:method).and_return(:get)
111
+ @request.stub!(:uri).and_return('http://www.example.com/code/404')
112
+ end
113
+
114
+ it 'should raise UnsuccessfulHttpRequestError' do
115
+ lambda {
116
+ @resource.do_read_request(:get)
117
+ }.should raise_error(Resourceful::UnsuccessfulHttpRequestError)
118
+ end
119
+
120
+ it 'should give a reasonable error message' do
121
+ lambda {
122
+ @resource.do_read_request(:get)
123
+ }.should raise_error("get request to <http://www.example.com/code/404> failed with code 404")
124
+ end
125
+ end
126
+
127
+ describe 'with redirection' do
128
+ before do
129
+ @uri = 'http://www.example.com/redirect/301?http://www.example.com/get'
130
+ @resource = Resourceful::Resource.new(@accessor, @uri)
131
+
132
+ @redirected_uri = 'http://www.example.com/get'
133
+ @redirect_response = mock('redirect_response',
134
+ :header => {'Location' => [@redirected_uri]},
135
+ :is_redirect? => true,
136
+ :is_permanent_redirect? => true,
137
+ :is_not_modified? => false)
138
+
139
+ @request.stub!(:response).and_return(@redirect_response, @response)
140
+
141
+ end
142
+
143
+ it 'should check if the response was a redirect' do
144
+ @redirect_response.should_receive(:is_redirect?).and_return(true)
145
+ make_request
146
+ end
147
+
148
+ it 'should check if the request should be redirected' do
149
+ @request.should_receive(:should_be_redirected?).and_return(true)
150
+ make_request
151
+ end
152
+
153
+ describe 'permanent redirect' do
154
+ before do
155
+ @redirect_response.stub!(:is_permanent_redirect?).and_return(true)
156
+ end
157
+
158
+ it 'should check if the response was a permanent redirect' do
159
+ @redirect_response.should_receive(:is_permanent_redirect?).and_return(true)
160
+ make_request
161
+ end
162
+
163
+ it 'should add the new location as the effective uri' do
164
+ make_request
165
+ @resource.effective_uri.should == @redirected_uri
166
+ end
167
+
168
+ it 'should remake the request with the new uri' do
169
+ Resourceful::Request.should_receive(:new).twice.and_return(@request)
170
+ @request.should_receive(:response).twice.and_return(@redirect_response, @response)
171
+ make_request
172
+ end
173
+
174
+ end
175
+
176
+ describe 'temporary redirect' do
177
+ before do
178
+ @redirect_response.stub!(:is_permanent_redirect?).and_return(false)
179
+ end
180
+
181
+ it 'should check if the response was not a permanent redirect' do
182
+ @redirect_response.should_receive(:is_permanent_redirect?).and_return(false)
183
+ make_request
184
+ end
185
+
186
+ it 'should not add the new location as the effective uri' do
187
+ make_request
188
+ @resource.effective_uri.should == @uri
189
+ end
190
+
191
+ it 'should make a new resource from the new location' do
192
+ new_resource = mock('resource', :do_read_request => @response, :uri => @uri)
193
+ Resourceful::Resource.should_receive(:new).with(@accessor, @redirected_uri).and_return(new_resource)
194
+ make_request
195
+ end
196
+
197
+ end
198
+
199
+ end # read with redirection
200
+
201
+ describe 'with authorization' do
202
+ before do
203
+ @authmgr = mock('auth_manager')
204
+ @authmgr.stub!(:add_credentials)
205
+ @authmgr.stub!(:associate_auth_info).and_return(true)
206
+
207
+ @accessor.stub!(:auth_manager).and_return(@authmgr)
208
+ end
209
+
210
+ it 'should attempt to add credentials to the request' do
211
+ @authmgr.should_receive(:add_credentials).with(@request)
212
+ make_request
213
+ end
214
+
215
+ it 'should check if the response was not authorized' do
216
+ @response.should_receive(:is_not_authorized?).and_return(false)
217
+ make_request
218
+ end
219
+
220
+ it 'should associate the auth info in the response if it was not authorized' do
221
+ @authmgr.should_receive(:associate_auth_info).with(@response).and_return(true)
222
+ @response.stub!(:is_not_authorized?).and_return(true)
223
+ make_request
224
+ end
225
+
226
+ it 'should re-make the request only once if it was not authorized the first time' do
227
+ Resourceful::Request.should_receive(:new).with(:some_method, @resource, nil, {}).twice.and_return(@request)
228
+ @response.stub!(:is_not_authorized?).and_return(true)
229
+ make_request
230
+ end
231
+
232
+ end
233
+
234
+ describe 'with caching' do
235
+ before do
236
+ @cached_response = mock('cached response', :is_redirect? => false,
237
+ :is_not_authorized? => false,
238
+ :is_success? => true,
239
+ :stale? => false)
240
+ @cache_manager.stub!(:lookup).and_return(@cached_response)
241
+ end
242
+
243
+ it 'should lookup the request in the cache' do
244
+ @cache_manager.should_receive(:lookup).with(@request)
245
+ make_request
246
+ end
247
+
248
+ it 'should check if the cached response is stale' do
249
+ @cached_response.should_receive(:stale?).and_return(false)
250
+ make_request
251
+ end
252
+
253
+ describe 'in cache' do
254
+
255
+ end
256
+
257
+ describe 'in cache but stale' do
258
+
259
+ end
260
+
261
+ describe 'not in cache' do
262
+
263
+ end
264
+
265
+ end
266
+
267
+ end
268
+
269
+ describe '#do_write_request' do
270
+
271
+ def make_request
272
+ @resource.do_write_request(:some_method, "data")
273
+ end
274
+
275
+ it 'should make a new request object from the method' do
276
+ Resourceful::Request.should_receive(:new).with(:some_method, @resource, "data", anything).and_return(@request)
277
+ @resource.do_write_request(:some_method, "data")
278
+ end
279
+
280
+ describe 'default options' do
281
+ before do
282
+ @resource.default_options = {:foo => :bar}
283
+ end
284
+
285
+ it 'should merge the header with the default options' do
286
+ Resourceful::Request.should_receive(:new).with(anything, anything, anything, :foo => :bar).and_return(@request)
287
+ make_request
288
+ end
289
+
290
+ it 'should override any default header with the request header' do
291
+ Resourceful::Request.should_receive(:new).with(anything, anything, anything, :foo => :baz).and_return(@request)
292
+ @resource.do_write_request(:some_method, "data", :foo => :baz)
293
+ end
294
+ end
295
+
296
+ describe 'non-success responses' do
297
+ before do
298
+ @uri = 'http://www.example.com/code/404'
299
+ @resource = Resourceful::Resource.new(@accessor, @uri)
300
+
301
+ @redirected_uri = 'http://www.example.com/get'
302
+ @response = mock('response',
303
+ :header => {'Location' => [@redirected_uri]},
304
+ :is_redirect? => false,
305
+ :is_success? => false,
306
+ :is_not_authorized? => false,
307
+ :code => 404)
308
+
309
+ @request.stub!(:response).and_return(@response)
310
+ @request.stub!(:method).and_return(:post)
311
+ @request.stub!(:uri).and_return('http://www.example.com/code/404')
312
+ end
313
+
314
+ it 'should raise UnsuccessfulHttpRequestError' do
315
+ lambda {
316
+ @resource.do_write_request(:post, "data")
317
+ }.should raise_error(Resourceful::UnsuccessfulHttpRequestError)
318
+ end
319
+
320
+ it 'should give a reasonable error message' do
321
+ lambda {
322
+ @resource.do_write_request(:post, "data")
323
+ }.should raise_error("post request to <http://www.example.com/code/404> failed with code 404")
324
+ end
325
+ end
326
+
327
+ describe 'with redirection' do
328
+ before do
329
+ @uri = 'http://www.example.com/redirect/301?http://www.example.com/get'
330
+ @resource = Resourceful::Resource.new(@accessor, @uri)
331
+
332
+ @redirected_uri = 'http://www.example.com/get'
333
+ @redirect_response = mock('redirect_response',
334
+ :header => {'Location' => [@redirected_uri]},
335
+ :is_redirect? => true,
336
+ :is_permanent_redirect? => true)
337
+
338
+ @request.stub!(:response).and_return(@redirect_response, @response)
339
+
340
+ end
341
+
342
+ it 'should check if the response was a redirect' do
343
+ @redirect_response.should_receive(:is_redirect?).and_return(true)
344
+ make_request
345
+ end
346
+
347
+ it 'should check if the request should be redirected' do
348
+ @request.should_receive(:should_be_redirected?).and_return(true)
349
+ make_request
350
+ end
351
+
352
+ describe 'permanent redirect' do
353
+ before do
354
+ @redirect_response.stub!(:is_permanent_redirect?).and_return(true)
355
+ end
356
+
357
+ it 'should check if the response was a permanent redirect' do
358
+ @redirect_response.should_receive(:is_permanent_redirect?).and_return(true)
359
+ make_request
360
+ end
361
+
362
+ it 'should add the new location as the effective uri' do
363
+ make_request
364
+ @resource.effective_uri.should == @redirected_uri
365
+ end
366
+
367
+ it 'should remake the request with the new uri' do
368
+ Resourceful::Request.should_receive(:new).twice.and_return(@request)
369
+ @request.should_receive(:response).twice.and_return(@redirect_response, @response)
370
+ make_request
371
+ end
372
+
373
+ end
374
+
375
+ describe 'temporary redirect' do
376
+ before do
377
+ @redirect_response.stub!(:is_permanent_redirect?).and_return(false)
378
+ @redirect_response.stub!(:code).and_return(302)
379
+ end
380
+
381
+ it 'should check if the response was not a permanent redirect' do
382
+ @redirect_response.should_receive(:is_permanent_redirect?).and_return(false)
383
+ make_request
384
+ end
385
+
386
+ it 'should not add the new location as the effective uri' do
387
+ make_request
388
+ @resource.effective_uri.should == @uri
389
+ end
390
+
391
+ it 'should make a new resource from the new location' do
392
+ new_resource = mock('resource', :do_write_request => @response)
393
+ Resourceful::Resource.should_receive(:new).with(@accessor, @redirected_uri).and_return(new_resource)
394
+ make_request
395
+ end
396
+
397
+ describe '302 Found' do
398
+ before do
399
+ @new_resource = mock('resource')
400
+ Resourceful::Resource.should_receive(:new).with(@accessor, @redirected_uri).and_return(@new_resource)
401
+ @redirect_response.stub!(:code).and_return(303)
402
+ end
403
+
404
+ it 'should redirect to the new location with a GET request, regardless of the original method' do
405
+ @new_resource.should_receive(:do_read_request).with(:get, {}).and_return(@response)
406
+ make_request
407
+ end
408
+ end
409
+
410
+ end
411
+
412
+ end # write with redirection
413
+
414
+ describe 'with authorization' do
415
+ before do
416
+ @authmgr = mock('auth_manager')
417
+ @authmgr.stub!(:add_credentials)
418
+ @authmgr.stub!(:associate_auth_info).and_return(true)
419
+
420
+ @accessor.stub!(:auth_manager).and_return(@authmgr)
421
+ end
422
+
423
+ it 'should attempt to add credentials to the request' do
424
+ @authmgr.should_receive(:add_credentials).with(@request)
425
+ make_request
426
+ end
427
+
428
+ it 'should check if the response was not authorized' do
429
+ @response.should_receive(:is_not_authorized?).and_return(false)
430
+ make_request
431
+ end
432
+
433
+ it 'should associate the auth info in the response if it was not authorized' do
434
+ @authmgr.should_receive(:associate_auth_info).with(@response).and_return(true)
435
+ @response.stub!(:is_not_authorized?).and_return(true)
436
+ make_request
437
+ end
438
+
439
+ it 'should re-make the request only once if it was not authorized the first time' do
440
+ Resourceful::Request.should_receive(:new).with(:some_method, @resource, "data", {}).twice.and_return(@request)
441
+ @response.stub!(:is_not_authorized?).and_return(true)
442
+ make_request
443
+ end
444
+ end
445
+
446
+ end
447
+
448
+ describe 'callback registration' do
449
+ before do
450
+ @callback = mock('callback')
451
+ @callback.stub!(:call).and_return(true)
452
+
453
+ @resource.on_redirect { @callback.call }
454
+ end
455
+
456
+ it 'should store the callback when called with a block' do
457
+ @resource.on_redirect { true }
458
+
459
+ callback = @resource.instance_variable_get(:@on_redirect)
460
+ callback.should be_kind_of(Proc)
461
+ end
462
+
463
+ it 'should return the callback when called without a block' do
464
+ callback = lambda { "foo" }
465
+ @resource.on_redirect(&callback)
466
+ @resource.on_redirect.should == callback
467
+ end
468
+
469
+ end
470
+
471
+ describe '#get' do
472
+
473
+ it 'should be a method' do
474
+ @resource.should respond_to(:get)
475
+ end
476
+
477
+ it 'should pass :get to the #do_read_request method' do
478
+ @resource.should_receive(:do_read_request).with(:get, {}).and_return(@response)
479
+ @resource.get
480
+ end
481
+
482
+ it 'should return the response of making the request' do
483
+ @resource.get.should == @response
484
+ end
485
+
486
+ end
487
+
488
+ describe "#delete" do
489
+
490
+ it 'should be a method' do
491
+ @resource.should respond_to(:delete)
492
+ end
493
+
494
+ it 'should return the response of making the request' do
495
+ @resource.delete.should == @response
496
+ end
497
+
498
+ end
499
+
500
+ describe "#post(body_data, :content_type => content-type)" do
501
+ before do
502
+ @resource = Resourceful::Resource.new(@accessor, 'http://foo.invalid/')
503
+ @response = mock('response', :is_redirect? => false, :is_success? => true, :is_not_authorized? => false, :code => 200)
504
+ @request = mock('request', :response => @response)
505
+ Resourceful::Request.stub!(:new).and_return(@request)
506
+ end
507
+
508
+ it "should get the response from the request" do
509
+ @request.should_receive(:response).and_return(@response)
510
+
511
+ @resource.post("a body", :content_type => 'text/plain')
512
+ end
513
+
514
+ it 'should put the content type in the header' do
515
+ Resourceful::Request.should_receive(:new).
516
+ with(anything,
517
+ anything,
518
+ anything,
519
+ hash_including(:content_type =>'text/plain')).
520
+ and_return(@request)
521
+
522
+ @resource.post("a body", :content_type => 'text/plain')
523
+ end
524
+
525
+ it 'should create a post request' do
526
+ Resourceful::Request.should_receive(:new).
527
+ with(:post, anything, anything, anything).
528
+ and_return(@request)
529
+
530
+ @resource.post("a body", :content_type => 'text/plain')
531
+ end
532
+
533
+ it 'should pass body to the request object' do
534
+ Resourceful::Request.should_receive(:new).
535
+ with(anything, anything, "a body", anything).
536
+ and_return(@request)
537
+
538
+ @resource.post("a body", :content_type => 'text/plain')
539
+ end
540
+
541
+ it 'should pass self to the request object' do
542
+ Resourceful::Request.should_receive(:new).
543
+ with(anything, @resource, anything, anything).
544
+ and_return(@request)
545
+
546
+ @resource.post("a body", :content_type => 'text/plain')
547
+ end
548
+ end
549
+
550
+ describe "#put(body_data, :content_type => content_type)" do
551
+ before do
552
+ @resource = Resourceful::Resource.new(@accessor, 'http://foo.invalid/')
553
+ @response = mock('response', :is_redirect? => false, :is_success? => true, :is_not_authorized? => false, :code => 200)
554
+ @request = mock('request', :response => @response)
555
+ Resourceful::Request.stub!(:new).and_return(@request)
556
+ end
557
+
558
+ it "should get the response from the request" do
559
+ @request.should_receive(:response).and_return(@response)
560
+
561
+ @resource.put("a body", :content_type => 'text/plain')
562
+ end
563
+
564
+ it 'should put the content type in the header' do
565
+ Resourceful::Request.should_receive(:new).
566
+ with(anything,
567
+ anything,
568
+ anything,
569
+ hash_including(:content_type =>'text/plain')).
570
+ and_return(@request)
571
+
572
+ @resource.put("a body", :content_type => 'text/plain')
573
+ end
574
+
575
+ it 'should create a put request' do
576
+ Resourceful::Request.should_receive(:new).
577
+ with(:put, anything, anything, anything).
578
+ and_return(@request)
579
+
580
+ @resource.put("a body", :content_type => 'text/plain')
581
+ end
582
+
583
+ it 'should pass body to the request object' do
584
+ Resourceful::Request.should_receive(:new).
585
+ with(anything, anything, "a body", anything).
586
+ and_return(@request)
587
+
588
+ @resource.put("a body", :content_type => 'text/plain')
589
+ end
590
+
591
+ it 'should pass self to the request object' do
592
+ Resourceful::Request.should_receive(:new).
593
+ with(anything, @resource, anything, anything).
594
+ and_return(@request)
595
+
596
+ @resource.put("a body", :content_type => 'text/plain')
597
+ end
598
+ end
599
+
600
+ end