resourceful 0.2.1 → 0.3.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.
@@ -2,8 +2,8 @@ require 'pathname'
2
2
  require Pathname(__FILE__).dirname + '../spec_helper'
3
3
 
4
4
  require 'resourceful/cache_manager'
5
-
6
- describe Resourceful::CacheManager do
5
+
6
+ describe Resourceful::AbstractCacheManager do
7
7
  before do
8
8
  @cm = Resourceful::InMemoryCacheManager.new #cheat, because I cant new a real one.
9
9
  end
@@ -19,40 +19,10 @@ describe Resourceful::CacheManager do
19
19
  it 'should have a store method' do
20
20
  @cm.should respond_to(:store)
21
21
  end
22
-
22
+
23
23
  it 'should have a invalidate method' do
24
24
  @cm.should respond_to(:invalidate)
25
25
  end
26
-
27
- describe '#select_request_headers' do
28
- before do
29
- @req_header = mock('header', :[] => nil)
30
- @request = mock('request', :header => @req_header)
31
-
32
- @resp_header = mock('header', :[] => nil)
33
- @response = mock('response', :header => @resp_header)
34
- end
35
-
36
- it 'should select the request headers from the Vary header' do
37
- @resp_header.should_receive(:[]).with('Vary')
38
- @cm.select_request_headers(@request, @response)
39
- end
40
-
41
- it 'should pull the values from the request that match keys in the vary header' do
42
- @resp_header.should_receive(:[]).with('Vary').twice.and_return(['foo, bar'])
43
- @req_header.should_receive(:[]).with('foo').and_return('oof')
44
- @req_header.should_receive(:[]).with('bar').and_return('rab')
45
-
46
- header = @cm.select_request_headers(@request, @response)
47
- header['foo'].should == 'oof'
48
- header['bar'].should == 'rab'
49
- end
50
-
51
- it 'should return a new Header object' do
52
- @cm.select_request_headers(@request, @response).should be_kind_of(Resourceful::Header)
53
- end
54
- end
55
-
56
26
  end
57
27
 
58
28
  describe Resourceful::NullCacheManager do
@@ -80,7 +50,7 @@ describe Resourceful::InMemoryCacheManager do
80
50
  @response = mock('response', :header => {}, :cachable? => true)
81
51
 
82
52
  @entry = mock('cache entry', :response => @response, :valid_for? => true)
83
- Resourceful::InMemoryCacheManager::CacheEntry.stub!(:new).and_return(@entry)
53
+ Resourceful::CacheEntry.stub!(:new).and_return(@entry)
84
54
 
85
55
  @imcm = Resourceful::InMemoryCacheManager.new
86
56
  end
@@ -88,7 +58,7 @@ describe Resourceful::InMemoryCacheManager do
88
58
  describe 'finding' do
89
59
  before do
90
60
  @response.stub!(:authoritative=)
91
- @imcm.instance_variable_set("@collection", {'uri' => {@request => @entry}})
61
+ @imcm.instance_variable_set("@collection", {'uri' => {@request => @response}})
92
62
  end
93
63
 
94
64
  it 'should lookup the response by request' do
@@ -103,9 +73,8 @@ describe Resourceful::InMemoryCacheManager do
103
73
 
104
74
  describe 'saving' do
105
75
  it 'should make a new cache entry' do
106
- Resourceful::InMemoryCacheManager::CacheEntry.should_receive(:new).with(
107
- Time.utc(2008,5,22,15,00),
108
- {},
76
+ Resourceful::CacheEntry.should_receive(:new).with(
77
+ @request,
109
78
  @response
110
79
  )
111
80
 
@@ -115,7 +84,7 @@ describe Resourceful::InMemoryCacheManager do
115
84
  it 'should store the response entity by request' do
116
85
  @imcm.store(@request, @response)
117
86
  col = @imcm.instance_variable_get("@collection")
118
- col['uri'][@request].response.should == @response
87
+ col['uri'][@request].should == @response
119
88
  end
120
89
 
121
90
  it 'should check if the response is cachable' do
@@ -142,20 +111,21 @@ describe Resourceful::InMemoryCacheManager do
142
111
 
143
112
  end
144
113
 
145
- describe Resourceful::InMemoryCacheManager::CacheEntryCollection do
114
+ describe Resourceful::CacheEntryCollection do
146
115
  before do
147
- @entry_valid = mock('entry', :valid_for? => true)
148
- @entry_invalid = mock('entry', :valid_for? => false)
116
+ @request = mock('request', :uri => 'this', :request_time => Time.now, :header => {})
117
+ @valid_resp = stub('valid_resp', :authoritative= => nil, :header => {})
149
118
 
150
- @request = mock('request')
119
+ @entry_valid = mock('entry', :valid_for? => true, :response => @valid_resp)
120
+ @entry_invalid = mock('entry', :valid_for? => false, :response => stub('invalid_resp'))
151
121
 
152
- @collection = Resourceful::InMemoryCacheManager::CacheEntryCollection.new
122
+ @collection = Resourceful::CacheEntryCollection.new
153
123
  end
154
124
 
155
125
  it 'should find the right entry for a request' do
156
126
  @collection.instance_variable_set('@entries', [@entry_valid, @entry_invalid])
157
127
  @entry_valid.should_receive(:valid_for?).with(@request).and_return(true)
158
- @collection[@request].should == @entry_valid
128
+ @collection[@request].should == @valid_resp
159
129
  end
160
130
 
161
131
  it 'should be nil if no matching entry was found' do
@@ -165,47 +135,89 @@ describe Resourceful::InMemoryCacheManager::CacheEntryCollection do
165
135
  end
166
136
 
167
137
  it 'should store an entry' do
168
- @collection[@request] = @entry_valid
169
- @collection.instance_variable_get("@entries").should include(@entry_valid)
138
+ @collection[@request] = @valid_resp
139
+ @collection.instance_variable_get("@entries").should have(1).items
170
140
  end
171
141
 
172
142
  it 'should replace an existing entry if the existing entry matches the request' do
173
- @new_entry = mock('entry', :valid_for? => true)
143
+ new_resp = stub('new_resp', :authoritative= => nil, :header => {})
174
144
 
175
- @collection[@request] = @entry_valid
176
- @collection[@request] = @new_entry
145
+ @collection[@request] = @valid_resp
146
+ @collection[@request] = new_resp
177
147
 
178
- @collection.instance_variable_get("@entries").should include(@new_entry)
179
- @collection.instance_variable_get("@entries").should_not include(@entry_valid)
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)
180
150
  end
181
151
 
182
152
  end
183
153
 
184
- describe Resourceful::InMemoryCacheManager::CacheEntry do
154
+ describe Resourceful::CacheEntry do
185
155
  before do
186
- @entry = Resourceful::InMemoryCacheManager::CacheEntry.new(
187
- Time.utc(2008,5,16,0,0,0), {'Content-Type' => 'text/plain'}, mock('response')
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'})
188
160
  )
189
161
 
190
- @request = mock('request')
162
+ @request = mock('request', :uri => 'http://foo.invalid')
191
163
  end
192
164
 
193
- [:request_time, :request_vary_headers, :response, :valid_for?].each do |method|
194
- it "should respond to ##{method}" do
195
- @entry.should respond_to(method)
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
196
190
  end
197
191
  end
198
192
 
199
- it 'should be valid for a request if all the vary headers match' do
200
- @request.stub!(:header).and_return({'Content-Type' => 'text/plain'})
201
- @entry.valid_for?(@request).should be_true
202
- end
193
+ describe '#select_request_headers' do
194
+ before do
195
+ @req_header = mock('header', :[] => nil)
196
+ @request = mock('request', :header => @req_header)
203
197
 
204
- it 'should not be valid for a request if not all the vary headers match' do
205
- @request.stub!(:header).and_return({'Content-Type' => 'text/html'})
206
- @entry.valid_for?(@request).should be_false
207
- end
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')
208
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
209
221
  end
210
222
 
211
223
 
@@ -23,20 +23,26 @@ describe Resourceful::HttpAccessor, 'init' do
23
23
 
24
24
  it 'should raise arg error if unrecognized options are passed' do
25
25
  lambda {
26
- ha = Resourceful::HttpAccessor.new(:foo => 'foo', :bar => 'bar')
26
+ Resourceful::HttpAccessor.new(:foo => 'foo', :bar => 'bar')
27
27
  }.should raise_error(ArgumentError, /Unrecognized options: (foo, bar)|(bar, foo)/)
28
28
  end
29
29
 
30
30
  it 'should allow an additional user agent token to be passed at init' do
31
- Resourceful::HttpAccessor.new(:user_agent => "Super/3000").tap do |ha|
32
- ha.user_agent_string.should match(%r{^Super/3000})
33
- end
31
+ ha = Resourceful::HttpAccessor.new(:user_agent => "Super/3000")
32
+
33
+ ha.user_agent_string.should match(%r{^Super/3000})
34
34
  end
35
35
 
36
36
  it 'should allow multiple additional user agent tokens to be passed at init' do
37
- Resourceful::HttpAccessor.new(:user_agent => ["Super/3000", "Duper/2.1"]).tap do |ha|
38
- ha.user_agent_string.should match(%r{^Super/3000 Duper/2\.1 })
39
- end
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)
40
46
  end
41
47
 
42
48
  end
@@ -87,13 +93,13 @@ describe Resourceful::HttpAccessor do
87
93
  end
88
94
 
89
95
  it 'should pass uri to resource upon creation (#[])' do
90
- Resourceful::Resource.should_receive(:new).with(anything, 'http://www.example/previously-unused-uri').
96
+ Resourceful::Resource.should_receive(:new).with(anything, 'http://www.example/previously-unused-uri', anything).
91
97
  and_return(stub('resource'))
92
98
  @accessor['http://www.example/previously-unused-uri']
93
99
  end
94
100
 
95
101
  it 'should pass owning accessor to resource upon creation (#[])' do
96
- Resourceful::Resource.should_receive(:new).with(@accessor, anything).and_return(stub('resource'))
102
+ Resourceful::Resource.should_receive(:new).with(@accessor, anything, anything).and_return(stub('resource'))
97
103
  @accessor['http://www.example/previously-unused-uri']
98
104
  end
99
105
 
@@ -107,14 +113,52 @@ describe Resourceful::HttpAccessor do
107
113
  end
108
114
 
109
115
  it 'should pass owning accessor to resource upon creation (#[])' do
110
- Resourceful::Resource.should_receive(:new).with(@accessor, anything).and_return(stub('resource'))
116
+ Resourceful::Resource.should_receive(:new).with(@accessor, anything, anything).and_return(stub('resource'))
111
117
  @accessor.resource('http://www.example/previously-unused-uri')
112
118
  end
113
119
 
114
120
  it 'should pass uri to resource upon creation (#resource)' do
115
- Resourceful::Resource.should_receive(:new).with(anything, 'http://www.example/previously-unused-uri').
121
+ Resourceful::Resource.should_receive(:new).with(anything, 'http://www.example/previously-unused-uri', anything).
116
122
  and_return(stub('resource'))
117
123
  @accessor.resource('http://www.example/previously-unused-uri')
118
124
  end
119
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
+
120
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
@@ -0,0 +1,111 @@
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
+
@@ -62,7 +62,15 @@ describe Resourceful::OptionsInterpreter, '#interpret(options)' do
62
62
  @interpreter.interpret({}).keys.should_not include(:foo)
63
63
  end
64
64
 
65
- it 'should not invoked option value munging block if option is not specified'
65
+ it 'should not invoked option value munging block if option is not specified' do
66
+ @interpreter = Resourceful::OptionsInterpreter.new()
67
+ munging_block_executed = false
68
+ @interpreter.option(:foo) { |a| munging_block_executed = true }
69
+
70
+ lambda {
71
+ @interpreter.interpret({})
72
+ }.should_not change{munging_block_executed}
73
+ end
66
74
 
67
75
  it 'should use default if option is not specified' do
68
76
  @interpreter = Resourceful::OptionsInterpreter.new()