resourceful 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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()