resourceful 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,204 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname + '../spec_helper'
3
+
4
+ require 'resourceful/authentication_manager'
5
+
6
+ describe Resourceful::AuthenticationManager do
7
+
8
+ before do
9
+ @authmgr = Resourceful::AuthenticationManager.new
10
+
11
+ @authenticator = mock('Authenticator')
12
+ end
13
+
14
+ [:add_auth_handler, :associate_auth_info, :add_credentials].each do |meth|
15
+ it "should have ##{meth}" do
16
+ @authmgr.should respond_to(meth)
17
+ end
18
+ end
19
+
20
+ it 'should add an authenticator to its list' do
21
+ @authmgr.add_auth_handler(@authenticator)
22
+ @authmgr.instance_variable_get("@authenticators").should include(@authenticator)
23
+ end
24
+
25
+ describe 'associating authenticators with challanges' do
26
+ before do
27
+ @authmgr.add_auth_handler(@authenticator)
28
+ @authenticator.stub!(:valid_for?).and_return(true)
29
+ @authenticator.stub!(:update_credentials)
30
+ @challenge = mock('Response')
31
+ end
32
+
33
+ it 'should check that an authenticator is valid for a challenge' do
34
+ @authenticator.should_receive(:valid_for?).with(@challenge).and_return(true)
35
+ @authmgr.associate_auth_info(@challenge)
36
+ end
37
+
38
+ it 'should update the credentials of the authenticator if it is valid for the challenge' do
39
+ @authenticator.should_receive(:update_credentials).with(@challenge)
40
+ @authmgr.associate_auth_info(@challenge)
41
+ end
42
+
43
+ it 'should not update the credentials of the authenticator if it is not valid for the challenge' do
44
+ @authenticator.stub!(:valid_for?).and_return(false)
45
+ @authenticator.should_not_receive(:update_credentials).with(@challenge)
46
+ @authmgr.associate_auth_info(@challenge)
47
+ end
48
+
49
+ end
50
+
51
+ describe 'adding credentials to a request' do
52
+ before do
53
+ @authmgr.add_auth_handler(@authenticator)
54
+ @authenticator.stub!(:can_handle?).and_return(true)
55
+ @authenticator.stub!(:add_credentials_to)
56
+ @request = mock('Request')
57
+ end
58
+
59
+ it 'should find an authenticator that can handle the request' do
60
+ @authenticator.should_receive(:can_handle?).with(@request).and_return(true)
61
+ @authmgr.add_credentials(@request)
62
+ end
63
+
64
+ it 'should add the authenticators credentials to the request' do
65
+ @authenticator.should_receive(:add_credentials_to).with(@request)
66
+ @authmgr.add_credentials(@request)
67
+ end
68
+
69
+ it 'should not add the authenticators credentials to the request if it cant handle it' do
70
+ @authenticator.should_receive(:can_handle?).with(@request).and_return(false)
71
+ @authenticator.should_not_receive(:add_credentials_to).with(@request)
72
+ @authmgr.add_credentials(@request)
73
+ end
74
+
75
+ end
76
+
77
+ end
78
+
79
+ describe Resourceful::BasicAuthenticator do
80
+ before do
81
+ @auth = Resourceful::BasicAuthenticator.new('Test Auth', 'admin', 'secret')
82
+ end
83
+
84
+ {:realm => 'Test Auth', :username => 'admin', :password => 'secret'}.each do |meth,val|
85
+ it "should initialize with a #{meth}" do
86
+ @auth.instance_variable_get("@#{meth}").should == val
87
+ end
88
+ end
89
+
90
+ describe "Updating from a challenge response" do
91
+ before do
92
+ @header = {'WWW-Authenticate' => ['Basic realm="Test Auth"']}
93
+ @chal = mock('response', :header => @header, :uri => 'http://example.com/foo/bar')
94
+ end
95
+
96
+ it 'should be valid for a challenge response with scheme "Basic" and the same realm' do
97
+ @auth.valid_for?(@chal).should be_true
98
+ end
99
+
100
+ it 'should be valid for a challenge response with multiple schemes including matchin "Basic" challenge' do
101
+ @header = {'WWW-Authenticate' => ['Digest some other stuff', 'Basic realm="Test Auth"', 'Weird scheme']}
102
+
103
+ @auth.valid_for?(@chal).should be_true
104
+ end
105
+
106
+ it 'should not be sensitive to case variances in the scheme' do
107
+ @header['WWW-Authenticate'] = ['bAsIc realm="Test Auth"']
108
+ @auth.valid_for?(@chal).should be_true
109
+ end
110
+
111
+ it 'should not be sensitive to case variances in the realm directive' do
112
+ @header['WWW-Authenticate'] = ['Basic rEaLm="Test Auth"']
113
+ @auth.valid_for?(@chal).should be_true
114
+ end
115
+
116
+ it 'should not be sensitive to case variances in the realm value' do
117
+ @header['WWW-Authenticate'] = ['Basic realm="test auth"']
118
+ @auth.valid_for?(@chal).should be_true
119
+ end
120
+
121
+ it 'should not be valid if the scheme is not "Basic"' do
122
+ @header['WWW-Authenticate'] = ["Digest"]
123
+ @auth.valid_for?(@chal).should be_false
124
+ end
125
+
126
+ it 'should not be valid if the realm does not match' do
127
+ @header['WWW-Authenticate'] = ['Basic realm="not test auth"']
128
+ @auth.valid_for?(@chal).should be_false
129
+ end
130
+
131
+ it 'should not be valid if the header is unreadable' do
132
+ @header['WWW-Authenticate'] = nil
133
+ @auth.valid_for?(@chal).should be_false
134
+ end
135
+
136
+ it 'should set the valid domain from the host part of the challenge uri' do
137
+ @auth.update_credentials(@chal)
138
+ @auth.instance_variable_get("@domain").should == 'example.com'
139
+ end
140
+
141
+ end
142
+
143
+ describe 'updating a request with credentials' do
144
+ before do
145
+ @auth.instance_variable_set("@domain", 'example.com')
146
+ @header = {}
147
+ @req = mock('request', :uri => 'http://example.com/bar/foo', :header => @header)
148
+ end
149
+
150
+ it 'should be able to handle a request for the matching domain' do
151
+ @auth.can_handle?(@req).should be_true
152
+ end
153
+
154
+ it 'should add credentials to a request' do
155
+ @header.should_receive(:[]=).with('Authorization', 'Basic YWRtaW46c2VjcmV0')
156
+ @auth.add_credentials_to(@req)
157
+ end
158
+
159
+ it 'should build the credentials string for the header' do
160
+ @auth.credentials.should == 'Basic YWRtaW46c2VjcmV0'
161
+ end
162
+ end
163
+
164
+ end
165
+
166
+ describe Resourceful::DigestAuthenticator do
167
+
168
+ before do
169
+ @auth = Resourceful::DigestAuthenticator.new('Test Auth', 'admin', 'secret')
170
+ end
171
+
172
+ {:realm => 'Test Auth', :username => 'admin', :password => 'secret'}.each do |meth,val|
173
+ it "should initialize with a #{meth}" do
174
+ @auth.instance_variable_get("@#{meth}").should == val
175
+ end
176
+ end
177
+
178
+ describe "Updating from a challenge response" do
179
+ before do
180
+ @header = {'WWW-Authenticate' => ['Digest realm="Test Auth"']}
181
+ @chal = mock('response', :header => @header, :uri => 'http://example.com/foo/bar')
182
+ end
183
+
184
+ it 'should be valid for a challenge response with scheme "Digest" and the same realm' do
185
+ @auth.valid_for?(@chal).should be_true
186
+ end
187
+
188
+ it 'should not be valid if the scheme is not "Digest"' do
189
+ @header['WWW-Authenticate'] = ["Basic"]
190
+ @auth.valid_for?(@chal).should be_false
191
+ end
192
+
193
+ it 'should not be valid if the realm does not match' do
194
+ @header['WWW-Authenticate'] = ['Digest realm="not test auth"']
195
+ @auth.valid_for?(@chal).should be_false
196
+ end
197
+
198
+ it 'should not be valid if the header is unreadable' do
199
+ @header['WWW-Authenticate'] = nil
200
+ @auth.valid_for?(@chal).should be_false
201
+ end
202
+ end
203
+
204
+ end
@@ -0,0 +1,202 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname + '../spec_helper'
3
+
4
+ require 'resourceful/cache_manager'
5
+
6
+ describe Resourceful::CacheManager 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
+ describe '#select_request_headers' do
24
+ before do
25
+ @req_header = mock('header', :[] => nil)
26
+ @request = mock('request', :header => @req_header)
27
+
28
+ @resp_header = mock('header', :[] => nil)
29
+ @response = mock('response', :header => @resp_header)
30
+ end
31
+
32
+ it 'should select the request headers from the Vary header' do
33
+ @resp_header.should_receive(:[]).with('Vary')
34
+ @cm.select_request_headers(@request, @response)
35
+ end
36
+
37
+ it 'should pull the values from the request that match keys in the vary header' do
38
+ @resp_header.should_receive(:[]).with('Vary').twice.and_return(['foo', 'bar'])
39
+ @req_header.should_receive(:[]).with('foo').and_return('oof')
40
+ @req_header.should_receive(:[]).with('bar').and_return('rab')
41
+
42
+ header = @cm.select_request_headers(@request, @response)
43
+ header['foo'].should == 'oof'
44
+ header['bar'].should == 'rab'
45
+ end
46
+
47
+ it 'should return a new Header object' do
48
+ @cm.select_request_headers(@request, @response).should be_kind_of(Resourceful::Header)
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ describe Resourceful::NullCacheManager do
55
+ before do
56
+ @ncm = Resourceful::NullCacheManager.new
57
+ end
58
+
59
+ it 'should not find anything' do
60
+ @ncm.lookup(:stuff).should be_nil
61
+ end
62
+
63
+ it 'should not store anything' do
64
+ @ncm.should respond_to(:store)
65
+
66
+ lambda { @ncm.store(:foo, :bar) }.should_not raise_error
67
+
68
+ end
69
+
70
+ end
71
+
72
+ describe Resourceful::InMemoryCacheManager do
73
+ before do
74
+ @request = mock('request', :resource => mock('resource', :uri => 'uri'),
75
+ :request_time => Time.utc(2008,5,22,15,00))
76
+ @response = mock('response', :header => {})
77
+
78
+ @entry = mock('cache entry', :response => @response, :valid_for? => true)
79
+ Resourceful::InMemoryCacheManager::CacheEntry.stub!(:new).and_return(@entry)
80
+
81
+ @imcm = Resourceful::InMemoryCacheManager.new
82
+ end
83
+
84
+ describe 'finding' do
85
+ before do
86
+ @response.stub!(:authoritative=)
87
+ @imcm.instance_variable_set("@collection", {'uri' => {@request => @entry}})
88
+ end
89
+
90
+ it 'should lookup the response by request' do
91
+ @imcm.lookup(@request).should == @response
92
+ end
93
+
94
+ it 'should set the response to non-authoritative' do
95
+ @response.should_receive(:authoritative=).with(false)
96
+ @imcm.lookup(@request)
97
+ end
98
+ end
99
+
100
+ describe 'saving' do
101
+ before do
102
+ @response.stub!(:cachable?).and_return(true)
103
+ end
104
+
105
+ 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
+ {},
109
+ @response
110
+ )
111
+
112
+ @imcm.store(@request, @response)
113
+ end
114
+
115
+ it 'should store the response entity by request' do
116
+ @imcm.store(@request, @response)
117
+ col = @imcm.instance_variable_get("@collection")
118
+ col['uri'][@request].response.should == @response
119
+ end
120
+
121
+ it 'should check if the response is cachable' do
122
+ @response.should_receive(:cachable?).and_return(true)
123
+ @imcm.store(@request, @response)
124
+ end
125
+
126
+ it 'should not store an entry if the response is not cachable' do
127
+ @response.should_receive(:cachable?).and_return(false)
128
+ @imcm.store(@request, @response)
129
+ col = @imcm.instance_variable_get("@collection")
130
+ col['uri'][@request].should be_nil
131
+ end
132
+ end
133
+
134
+ end
135
+
136
+ describe Resourceful::InMemoryCacheManager::CacheEntryCollection do
137
+ before do
138
+ @entry_valid = mock('entry', :valid_for? => true)
139
+ @entry_invalid = mock('entry', :valid_for? => false)
140
+
141
+ @request = mock('request')
142
+
143
+ @collection = Resourceful::InMemoryCacheManager::CacheEntryCollection.new
144
+ end
145
+
146
+ it 'should find the right entry for a request' do
147
+ @collection.instance_variable_set('@entries', [@entry_valid, @entry_invalid])
148
+ @entry_valid.should_receive(:valid_for?).with(@request).and_return(true)
149
+ @collection[@request].should == @entry_valid
150
+ end
151
+
152
+ it 'should be nil if no matching entry was found' do
153
+ @collection.instance_variable_set('@entries', [@entry_invalid])
154
+ @entry_invalid.should_receive(:valid_for?).with(@request).and_return(false)
155
+ @collection[@request].should == nil
156
+ end
157
+
158
+ it 'should store an entry' do
159
+ @collection[@request] = @entry_valid
160
+ @collection.instance_variable_get("@entries").should include(@entry_valid)
161
+ end
162
+
163
+ it 'should replace an existing entry if the existing entry matches the request' do
164
+ @new_entry = mock('entry', :valid_for? => true)
165
+
166
+ @collection[@request] = @entry_valid
167
+ @collection[@request] = @new_entry
168
+
169
+ @collection.instance_variable_get("@entries").should include(@new_entry)
170
+ @collection.instance_variable_get("@entries").should_not include(@entry_valid)
171
+ end
172
+
173
+ end
174
+
175
+ describe Resourceful::InMemoryCacheManager::CacheEntry do
176
+ before do
177
+ @entry = Resourceful::InMemoryCacheManager::CacheEntry.new(
178
+ Time.utc(2008,5,16,0,0,0), {'Content-Type' => 'text/plain'}, mock('response')
179
+ )
180
+
181
+ @request = mock('request')
182
+ end
183
+
184
+ [:request_time, :request_vary_headers, :response, :valid_for?].each do |method|
185
+ it "should respond to ##{method}" do
186
+ @entry.should respond_to(method)
187
+ end
188
+ end
189
+
190
+ it 'should be valid for a request if all the vary headers match' do
191
+ @request.stub!(:header).and_return({'Content-Type' => 'text/plain'})
192
+ @entry.valid_for?(@request).should be_true
193
+ end
194
+
195
+ it 'should not be valid for a request if not all the vary headers match' do
196
+ @request.stub!(:header).and_return({'Content-Type' => 'text/html'})
197
+ @entry.valid_for?(@request).should be_false
198
+ end
199
+
200
+ end
201
+
202
+
@@ -0,0 +1,38 @@
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
+
@@ -0,0 +1,120 @@
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::HttpAccessor::BitBucketLogger)
22
+ end
23
+
24
+ it 'should raise arg error if unrecognized options are passed' do
25
+ lambda {
26
+ ha = 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
+ Resourceful::HttpAccessor.new(:user_agent => "Super/3000").tap do |ha|
32
+ ha.user_agent_string.should match(%r{^Super/3000})
33
+ end
34
+ end
35
+
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
40
+ end
41
+
42
+ end
43
+
44
+ describe Resourceful::HttpAccessor do
45
+ before do
46
+ @logger = stub('logger')
47
+ @accessor = Resourceful::HttpAccessor.new(:logger => @logger)
48
+ @auth_manager = mock('authentication_manager')
49
+ Resourceful::AuthenticationManager.stub!(:new).and_return(@auth_manager)
50
+
51
+ @resource = mock('resource')
52
+ Resourceful::Resource.stub!(:new).and_return(@resource)
53
+ end
54
+
55
+ it 'should have user agent string w/ just resourceful token by default' do
56
+ @accessor.user_agent_string.should == "Resourceful/#{RESOURCEFUL_VERSION}(Ruby/#{RUBY_VERSION})"
57
+ end
58
+
59
+ it 'should add additional user agent tokens to beginning of user agent string' do
60
+ @accessor.user_agent_tokens << 'FooBar/3000(special-version)'
61
+
62
+ @accessor.user_agent_string.should match(%r{^FooBar\/3000\(special-version\) Resourceful/})
63
+ end
64
+
65
+ it 'should allow a logger to be specified' do
66
+ l = stub('logger')
67
+
68
+ @accessor.logger = l
69
+ @accessor.logger.should == l
70
+ end
71
+
72
+ it 'should allow a logger to be removed' do
73
+ l = stub('logger')
74
+
75
+ @accessor.logger = l
76
+ @accessor.logger = nil
77
+ @accessor.logger.should be_nil
78
+ end
79
+
80
+ it 'should be able to return a particular resource (#[])' do
81
+ @accessor['http://www.example/'].should == @resource
82
+ end
83
+
84
+ it 'should create resource if it does not already exist (#[])' do
85
+ Resourceful::Resource.should_receive(:new).and_return(stub('resource'))
86
+ @accessor['http://www.example/previously-unused-uri']
87
+ end
88
+
89
+ it 'should pass uri to resource upon creation (#[])' do
90
+ Resourceful::Resource.should_receive(:new).with(anything, 'http://www.example/previously-unused-uri').
91
+ and_return(stub('resource'))
92
+ @accessor['http://www.example/previously-unused-uri']
93
+ end
94
+
95
+ it 'should pass owning accessor to resource upon creation (#[])' do
96
+ Resourceful::Resource.should_receive(:new).with(@accessor, anything).and_return(stub('resource'))
97
+ @accessor['http://www.example/previously-unused-uri']
98
+ end
99
+
100
+ it 'should be able to return a particular resource (#resource)' do
101
+ @accessor.resource('http://www.example/').should == @resource
102
+ end
103
+
104
+ it 'should create resource if it does not already exist (#resource)' do
105
+ Resourceful::Resource.should_receive(:new).and_return(stub('resource'))
106
+ @accessor.resource('http://www.example/previously-unused-uri')
107
+ end
108
+
109
+ it 'should pass owning accessor to resource upon creation (#[])' do
110
+ Resourceful::Resource.should_receive(:new).with(@accessor, anything).and_return(stub('resource'))
111
+ @accessor.resource('http://www.example/previously-unused-uri')
112
+ end
113
+
114
+ it 'should pass uri to resource upon creation (#resource)' do
115
+ Resourceful::Resource.should_receive(:new).with(anything, 'http://www.example/previously-unused-uri').
116
+ and_return(stub('resource'))
117
+ @accessor.resource('http://www.example/previously-unused-uri')
118
+ end
119
+
120
+ end