paul-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 +30 -0
  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 +191 -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 +73 -0
  23. data/spec/simple_sinatra_server_spec.rb +98 -0
  24. data/spec/spec_helper.rb +21 -7
  25. metadata +55 -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,223 +0,0 @@
1
- require 'pathname'
2
- require Pathname(__FILE__).dirname + '../spec_helper'
3
-
4
- require 'resourceful/cache_manager'
5
-
6
- describe Resourceful::AbstractCacheManager do
7
- before do
8
- @cm = Resourceful::InMemoryCacheManager.new #cheat, because I cant new a real one.
9
- end
10
-
11
- it 'should not be initializable' do
12
- lambda { Resourceful::CacheManager.new }.should raise_error
13
- end
14
-
15
- it 'should have a lookup method' do
16
- @cm.should respond_to(:lookup)
17
- end
18
-
19
- it 'should have a store method' do
20
- @cm.should respond_to(:store)
21
- end
22
-
23
- it 'should have a invalidate method' do
24
- @cm.should respond_to(:invalidate)
25
- end
26
- end
27
-
28
- describe Resourceful::NullCacheManager do
29
- before do
30
- @ncm = Resourceful::NullCacheManager.new
31
- end
32
-
33
- it 'should not find anything' do
34
- @ncm.lookup(:stuff).should be_nil
35
- end
36
-
37
- it 'should not store anything' do
38
- @ncm.should respond_to(:store)
39
-
40
- lambda { @ncm.store(:foo, :bar) }.should_not raise_error
41
- end
42
-
43
- end
44
-
45
- describe Resourceful::InMemoryCacheManager do
46
- before do
47
- @request = mock('request', :resource => mock('resource'),
48
- :request_time => Time.utc(2008,5,22,15,00),
49
- :uri => 'uri')
50
- @response = mock('response', :header => {}, :cachable? => true)
51
-
52
- @entry = mock('cache entry', :response => @response, :valid_for? => true)
53
- Resourceful::CacheEntry.stub!(:new).and_return(@entry)
54
-
55
- @imcm = Resourceful::InMemoryCacheManager.new
56
- end
57
-
58
- describe 'finding' do
59
- before do
60
- @response.stub!(:authoritative=)
61
- @imcm.instance_variable_set("@collection", {'uri' => {@request => @response}})
62
- end
63
-
64
- it 'should lookup the response by request' do
65
- @imcm.lookup(@request).should == @response
66
- end
67
-
68
- it 'should set the response to non-authoritative' do
69
- @response.should_receive(:authoritative=).with(false)
70
- @imcm.lookup(@request)
71
- end
72
- end
73
-
74
- describe 'saving' do
75
- it 'should make a new cache entry' do
76
- Resourceful::CacheEntry.should_receive(:new).with(
77
- @request,
78
- @response
79
- )
80
-
81
- @imcm.store(@request, @response)
82
- end
83
-
84
- it 'should store the response entity by request' do
85
- @imcm.store(@request, @response)
86
- col = @imcm.instance_variable_get("@collection")
87
- col['uri'][@request].should == @response
88
- end
89
-
90
- it 'should check if the response is cachable' do
91
- @response.should_receive(:cachable?).and_return(true)
92
- @imcm.store(@request, @response)
93
- end
94
-
95
- it 'should not store an entry if the response is not cachable' do
96
- @response.should_receive(:cachable?).and_return(false)
97
- @imcm.store(@request, @response)
98
- col = @imcm.instance_variable_get("@collection")
99
- col['uri'][@request].should be_nil
100
- end
101
- end
102
-
103
- describe 'invalidating' do
104
- it 'should remove an entry from the cache by uri' do
105
- @imcm.store(@request, @response)
106
- @imcm.invalidate('uri')
107
- col = @imcm.instance_variable_get("@collection")
108
- col.should_not have_key('uri')
109
- end
110
- end
111
-
112
- end
113
-
114
- describe Resourceful::CacheEntryCollection do
115
- before do
116
- @request = mock('request', :uri => 'this', :request_time => Time.now, :header => {})
117
- @valid_resp = stub('valid_resp', :authoritative= => nil, :header => {})
118
-
119
- @entry_valid = mock('entry', :valid_for? => true, :response => @valid_resp)
120
- @entry_invalid = mock('entry', :valid_for? => false, :response => stub('invalid_resp'))
121
-
122
- @collection = Resourceful::CacheEntryCollection.new
123
- end
124
-
125
- it 'should find the right entry for a request' do
126
- @collection.instance_variable_set('@entries', [@entry_valid, @entry_invalid])
127
- @entry_valid.should_receive(:valid_for?).with(@request).and_return(true)
128
- @collection[@request].should == @valid_resp
129
- end
130
-
131
- it 'should be nil if no matching entry was found' do
132
- @collection.instance_variable_set('@entries', [@entry_invalid])
133
- @entry_invalid.should_receive(:valid_for?).with(@request).and_return(false)
134
- @collection[@request].should == nil
135
- end
136
-
137
- it 'should store an entry' do
138
- @collection[@request] = @valid_resp
139
- @collection.instance_variable_get("@entries").should have(1).items
140
- end
141
-
142
- it 'should replace an existing entry if the existing entry matches the request' do
143
- new_resp = stub('new_resp', :authoritative= => nil, :header => {})
144
-
145
- @collection[@request] = @valid_resp
146
- @collection[@request] = new_resp
147
-
148
- @collection.instance_variable_get("@entries").map{|it| it.response}.should include(new_resp)
149
- @collection.instance_variable_get("@entries").map{|it| it.response}.should_not include(@valid_resp)
150
- end
151
-
152
- end
153
-
154
- describe Resourceful::CacheEntry do
155
- before do
156
- @entry = Resourceful::CacheEntry.new(
157
- mock('original_request', :header => {'Accept' => 'text/plain'} ,
158
- :request_time => Time.utc(2008,5,16,0,0,0), :uri => 'http://foo.invalid'),
159
- mock('response', :header => {'Vary' => 'Accept'})
160
- )
161
-
162
- @request = mock('request', :uri => 'http://foo.invalid')
163
- end
164
-
165
- describe "#valid_for?(a_request)" do
166
- it "should true for request to URI w/ matching header " do
167
- @entry.valid_for?(mock("new_request",
168
- :uri => 'http://foo.invalid',
169
- :header => {'Accept' => 'text/plain'})).should be_true
170
- end
171
-
172
- it "should false for requests against different URIs even if headers match" do
173
- @entry.valid_for?(mock("new_request", :uri => 'http://bar.invalid',
174
- :header => {'Accept' => 'text/plain'})).should be_false
175
- end
176
-
177
- it "should false for requests where headers don't match" do
178
- @entry.valid_for?(mock("new_request", :uri => 'http://foo.invalid',
179
- :header => {'Accept' => 'application/octet-stream'})).should be_false
180
- end
181
-
182
- it "should be false if request has a varying header and the original request was missing that header" do
183
- entry = Resourceful::CacheEntry.new(
184
- mock('original_request', :header => {},
185
- :request_time => Time.utc(2008,5,16,0,0,0), :uri => 'http://foo.invalid'),
186
- mock('response', :header => {'Vary' => 'Accept'}))
187
-
188
- entry.valid_for?(mock("new_request", :uri => 'http://foo.invalid',
189
- :header => {'Accept' => 'text/plain'})).should be_false
190
- end
191
- end
192
-
193
- describe '#select_request_headers' do
194
- before do
195
- @req_header = mock('header', :[] => nil)
196
- @request = mock('request', :header => @req_header)
197
-
198
- @resp_header = mock('header', :[] => nil)
199
- @response = mock('response', :header => @resp_header)
200
- end
201
-
202
- it 'should select the request headers from the Vary header' do
203
- @resp_header.should_receive(:[]).with('Vary')
204
- @entry.select_request_headers(@request, @response)
205
- end
206
-
207
- it 'should pull the values from the request that match keys in the vary header' do
208
- @resp_header.should_receive(:[]).with('Vary').twice.and_return(['foo', 'bar'])
209
- @req_header.should_receive(:[]).with('foo').and_return('oof')
210
- @req_header.should_receive(:[]).with('bar').and_return('rab')
211
-
212
- header = @entry.select_request_headers(@request, @response)
213
- header['foo'].should == 'oof'
214
- header['bar'].should == 'rab'
215
- end
216
-
217
- it 'should return a new Header object' do
218
- @entry.select_request_headers(@request, @response).should be_kind_of(Resourceful::Header)
219
- end
220
- end
221
- end
222
-
223
-
@@ -1,38 +0,0 @@
1
- require 'pathname'
2
- require Pathname(__FILE__).dirname + '../spec_helper'
3
-
4
- require 'resourceful/header'
5
-
6
- describe Resourceful::Header do
7
-
8
- it "should capitalize on all accesses" do
9
- h = Resourceful::Header.new("foo" => "bar")
10
- h["foo"].should == "bar"
11
- h["Foo"].should == "bar"
12
- h["FOO"].should == "bar"
13
-
14
- h.to_hash.should == {"Foo" => "bar"}
15
-
16
- h["bar-zzle"] = "quux"
17
-
18
- h.to_hash.should == {"Foo" => "bar", "Bar-Zzle" => "quux"}
19
- end
20
-
21
- it "should capitalize correctly" do
22
- h = Resourceful::Header.new
23
-
24
- h.capitalize("foo").should == "Foo"
25
- h.capitalize("foo-bar").should == "Foo-Bar"
26
- h.capitalize("foo_bar").should == "Foo-Bar"
27
- h.capitalize("foo bar").should == "Foo Bar"
28
- h.capitalize("foo-bar-quux").should == "Foo-Bar-Quux"
29
- h.capitalize("foo-bar-2quux").should == "Foo-Bar-2quux"
30
- end
31
-
32
- it "should be converted to real Hash" do
33
- h = Resourceful::Header.new("foo" => "bar")
34
- h.to_hash.should be_instance_of(Hash)
35
- end
36
-
37
- end
38
-
@@ -1,164 +0,0 @@
1
- require 'pathname'
2
- require Pathname(__FILE__).dirname + '../spec_helper'
3
-
4
- require 'resourceful/http_accessor'
5
-
6
- describe Resourceful::HttpAccessor, 'init' do
7
-
8
- it 'should be instantiatable' do
9
- Resourceful::HttpAccessor.new().should be_instance_of(Resourceful::HttpAccessor)
10
- end
11
-
12
- it 'should accept logger to new' do
13
- ha = Resourceful::HttpAccessor.new(:logger => (l = stub('logger')))
14
-
15
- ha.logger.should == l
16
- end
17
-
18
- it 'should provide logger object even when no logger is specified' do
19
- ha = Resourceful::HttpAccessor.new()
20
-
21
- ha.logger.should be_instance_of(Resourceful::BitBucketLogger)
22
- end
23
-
24
- it 'should raise arg error if unrecognized options are passed' do
25
- lambda {
26
- Resourceful::HttpAccessor.new(:foo => 'foo', :bar => 'bar')
27
- }.should raise_error(ArgumentError, /Unrecognized options: (foo, bar)|(bar, foo)/)
28
- end
29
-
30
- it 'should allow an additional user agent token to be passed at init' do
31
- ha = Resourceful::HttpAccessor.new(:user_agent => "Super/3000")
32
-
33
- ha.user_agent_string.should match(%r{^Super/3000})
34
- end
35
-
36
- it 'should allow multiple additional user agent tokens to be passed at init' do
37
- ha = Resourceful::HttpAccessor.new(:user_agent => ["Super/3000", "Duper/2.1"])
38
-
39
- ha.user_agent_string.should match(%r{^Super/3000 Duper/2\.1 })
40
- end
41
-
42
- it 'should allow cache manager to be provided at init' do
43
- ha = Resourceful::HttpAccessor.new(:cache_manager => :marker)
44
-
45
- ha.cache_manager.should equal(:marker)
46
- end
47
-
48
- end
49
-
50
- describe Resourceful::HttpAccessor do
51
- before do
52
- @logger = stub('logger')
53
- @accessor = Resourceful::HttpAccessor.new(:logger => @logger)
54
- @auth_manager = mock('authentication_manager')
55
- Resourceful::AuthenticationManager.stub!(:new).and_return(@auth_manager)
56
-
57
- @resource = mock('resource')
58
- Resourceful::Resource.stub!(:new).and_return(@resource)
59
- end
60
-
61
- it 'should have user agent string w/ just resourceful token by default' do
62
- @accessor.user_agent_string.should == "Resourceful/#{RESOURCEFUL_VERSION}(Ruby/#{RUBY_VERSION})"
63
- end
64
-
65
- it 'should add additional user agent tokens to beginning of user agent string' do
66
- @accessor.user_agent_tokens << 'FooBar/3000(special-version)'
67
-
68
- @accessor.user_agent_string.should match(%r{^FooBar\/3000\(special-version\) Resourceful/})
69
- end
70
-
71
- it 'should allow a logger to be specified' do
72
- l = stub('logger')
73
-
74
- @accessor.logger = l
75
- @accessor.logger.should == l
76
- end
77
-
78
- it 'should allow a logger to be removed' do
79
- l = stub('logger')
80
-
81
- @accessor.logger = l
82
- @accessor.logger = nil
83
- @accessor.logger.should be_nil
84
- end
85
-
86
- it 'should be able to return a particular resource (#[])' do
87
- @accessor['http://www.example/'].should == @resource
88
- end
89
-
90
- it 'should create resource if it does not already exist (#[])' do
91
- Resourceful::Resource.should_receive(:new).and_return(stub('resource'))
92
- @accessor['http://www.example/previously-unused-uri']
93
- end
94
-
95
- it 'should pass uri to resource upon creation (#[])' do
96
- Resourceful::Resource.should_receive(:new).with(anything, 'http://www.example/previously-unused-uri', anything).
97
- and_return(stub('resource'))
98
- @accessor['http://www.example/previously-unused-uri']
99
- end
100
-
101
- it 'should pass owning accessor to resource upon creation (#[])' do
102
- Resourceful::Resource.should_receive(:new).with(@accessor, anything, anything).and_return(stub('resource'))
103
- @accessor['http://www.example/previously-unused-uri']
104
- end
105
-
106
- it 'should be able to return a particular resource (#resource)' do
107
- @accessor.resource('http://www.example/').should == @resource
108
- end
109
-
110
- it 'should create resource if it does not already exist (#resource)' do
111
- Resourceful::Resource.should_receive(:new).and_return(stub('resource'))
112
- @accessor.resource('http://www.example/previously-unused-uri')
113
- end
114
-
115
- it 'should pass owning accessor to resource upon creation (#[])' do
116
- Resourceful::Resource.should_receive(:new).with(@accessor, anything, anything).and_return(stub('resource'))
117
- @accessor.resource('http://www.example/previously-unused-uri')
118
- end
119
-
120
- it 'should pass uri to resource upon creation (#resource)' do
121
- Resourceful::Resource.should_receive(:new).with(anything, 'http://www.example/previously-unused-uri', anything).
122
- and_return(stub('resource'))
123
- @accessor.resource('http://www.example/previously-unused-uri')
124
- end
125
-
126
- it 'should pass additional options to resource upon creation' do
127
- Resourceful::Resource.should_receive(:new).with(anything, anything, :foo => :bar).and_return(stub('resource'))
128
- @accessor.resource('http://example.com/', :foo => :bar)
129
- end
130
-
131
- end
132
-
133
- describe Resourceful::HttpAccessor, "(authentication)" do
134
- before do
135
- @auth_manager = stub('auth_manager', :add_auth_handler => nil)
136
- Resourceful::AuthenticationManager.stub!(:new).and_return(@auth_manager)
137
- @ha = Resourceful::HttpAccessor.new()
138
- end
139
-
140
- it 'should allow authenticators to be registered' do
141
- an_authenticator = stub('an_authenicator')
142
- @auth_manager.should_receive(:add_auth_handler).with(an_authenticator)
143
-
144
- @ha.add_authenticator(an_authenticator)
145
- end
146
-
147
- it 'should allow an authenicator to be specified at init' do
148
- an_authenticator = stub('an_authenicator')
149
- @auth_manager.should_receive(:add_auth_handler).with(an_authenticator)
150
-
151
- Resourceful::HttpAccessor.new(:authenticator => an_authenticator)
152
- end
153
-
154
- it 'should allow multiple authenicators to be specified at init' do
155
- authenticator1 = stub('authenicator1')
156
- authenticator2 = stub('authenicator2')
157
-
158
- @auth_manager.should_receive(:add_auth_handler).with(authenticator1)
159
- @auth_manager.should_receive(:add_auth_handler).with(authenticator2)
160
-
161
- Resourceful::HttpAccessor.new(:authenticators => [authenticator1, authenticator2])
162
- end
163
-
164
- end
@@ -1,111 +0,0 @@
1
- require 'pathname'
2
- require Pathname(__FILE__).dirname + '../spec_helper'
3
-
4
- require 'resourceful/memcache_cache_manager'
5
- require 'resourceful/request'
6
-
7
- describe Resourceful::MemcacheCacheManager do
8
- before do
9
- @resource = stub('resource', :uri => 'http://foo.invalid/')
10
-
11
- @request = Resourceful::Request.new(:get, @resource)
12
- @response = Resourceful::Response.new('http://foo.invalid/', '200', {'Vary' => 'Accept'}, "a body")
13
-
14
- @memcache = stub('memcache', :get => nil)
15
- MemCache.stub!(:new).and_return(@memcache)
16
-
17
- @cache_mngr = Resourceful::MemcacheCacheManager.new('foobar:42')
18
- end
19
-
20
- describe "#store(request,response)" do
21
- it "should store the new pair in memcache" do
22
- @memcache.should_receive(:[]=).with do |key, collection|
23
- key.should == Digest::MD5.hexdigest('http://foo.invalid/')
24
- collection[@request].should == @response
25
- end
26
-
27
- @cache_mngr.store(@request, @response)
28
- end
29
-
30
- it "should replace existing values if they exist" do
31
- entries = Resourceful::CacheEntryCollection.new
32
- entries[@request] = @response
33
- @memcache.stub!(:[]=).and_return(entries)
34
-
35
- new_request = Resourceful::Request.new(:get, @resource)
36
- new_response = Resourceful::Response.new('http://foo.invalid/', '200', {}, "a different body")
37
-
38
- @memcache.should_receive(:[]=).with do |key, collection|
39
- collection[new_request].should == new_response
40
- end
41
-
42
- @cache_mngr.store(new_request, new_response)
43
- end
44
-
45
- it "should not store responses that are not cacheable" do
46
- @memcache.should_not_receive(:[]=)
47
-
48
- vary_star_response = Resourceful::Response.new('http://foo.invalid/', '200', {'Vary' => '*'}, "a different body")
49
-
50
- @cache_mngr.store(@request, vary_star_response)
51
- end
52
- end
53
-
54
- describe "#lookup" do
55
- before do
56
- @entries = Resourceful::CacheEntryCollection.new
57
- @entries[@request] = @response
58
- @memcache.stub!(:get).and_return(@entries)
59
- end
60
-
61
- it "should lookup the entry collection by the URI" do
62
- @memcache.should_receive(:get).with(Digest::MD5.hexdigest('http://foo.invalid/')).and_return(@entries)
63
-
64
- @cache_mngr.lookup(@request)
65
- end
66
-
67
- it "should retrieve responses that match request" do
68
- @cache_mngr.lookup(Resourceful::Request.new(:get, @resource)).should == @response
69
- end
70
-
71
- it "should return nil if no responses that match request are found" do
72
- @cache_mngr.lookup(Resourceful::Request.new(:get, @resource, "body", {'Accept' => 'text/plain'})).
73
- should be_nil
74
- end
75
-
76
- it "should return nil if no responses that resource are found" do
77
- @memcache.stub!(:get).and_return(nil)
78
-
79
- @cache_mngr.lookup(Resourceful::Request.new(:get, @resource)).should be_nil
80
- end
81
- end
82
-
83
- describe "#invalidate(url)" do
84
- it "should remove all cached responses for that resource from memcache" do
85
- @memcache.should_receive(:delete).with(Digest::MD5.hexdigest('http://foo.invalid/'))
86
-
87
- @cache_mngr.invalidate('http://foo.invalid/')
88
- end
89
- end
90
- end
91
-
92
- describe Resourceful::MemcacheCacheManager, 'init' do
93
- it 'should be createable with single memcache server' do
94
- MemCache.should_receive(:new).with(['foobar:42'], anything)
95
-
96
- Resourceful::MemcacheCacheManager.new('foobar:42')
97
- end
98
-
99
- it 'should be createable with multiple memcache servers' do
100
- MemCache.should_receive(:new).with(['foobar:42', 'baz:32'], anything)
101
-
102
- Resourceful::MemcacheCacheManager.new('foobar:42', 'baz:32')
103
- end
104
-
105
- it 'should create a thread safe memcache client' do
106
- MemCache.should_receive(:new).with(anything, {:multithread => true})
107
-
108
- Resourceful::MemcacheCacheManager.new('foobar:42')
109
- end
110
- end
111
-