paul-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 +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
-