cassette 1.0.18 → 1.1.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.
- checksums.yaml +4 -4
- data/README.md +89 -12
- data/lib/cassette/authentication/authorities.rb +34 -30
- data/lib/cassette/authentication/cache.rb +22 -18
- data/lib/cassette/authentication/filter.rb +52 -33
- data/lib/cassette/authentication/user.rb +20 -16
- data/lib/cassette/authentication.rb +39 -27
- data/lib/cassette/cache.rb +2 -2
- data/lib/cassette/client/cache.rb +39 -35
- data/lib/cassette/client.rb +5 -4
- data/lib/cassette/http/parsed_response.rb +20 -0
- data/lib/cassette/http/request.rb +44 -0
- data/lib/cassette/http/ticket_response.rb +48 -0
- data/lib/cassette/http.rb +8 -0
- data/lib/cassette/rubycas/helper.rb +2 -8
- data/lib/cassette/rubycas/routing_constraint.rb +23 -0
- data/lib/cassette/rubycas/single_sign_out_constraint.rb +8 -8
- data/lib/cassette/rubycas/user_factory.rb +14 -0
- data/lib/cassette/rubycas.rb +2 -0
- data/lib/cassette/version.rb +2 -2
- data/lib/cassette.rb +12 -50
- data/spec/cassette/authentication/authorities_spec.rb +1 -1
- data/spec/cassette/authentication/cache_spec.rb +40 -4
- data/spec/cassette/authentication/filter_spec.rb +106 -36
- data/spec/cassette/authentication/user_factory_spec.rb +42 -0
- data/spec/cassette/authentication/user_spec.rb +4 -3
- data/spec/cassette/authentication_spec.rb +24 -12
- data/spec/cassette/cache_spec.rb +0 -2
- data/spec/cassette/client/cache_spec.rb +1 -1
- data/spec/cassette/client_spec.rb +319 -0
- data/spec/cassette/errors_spec.rb +1 -1
- data/spec/cassette/http/parsed_response_spec.rb +27 -0
- data/spec/cassette/http/request_spec.rb +41 -0
- data/spec/cassette/http/ticket_response_spec.rb +41 -0
- data/spec/cassette/rubycas/routing_constraint_spec.rb +84 -0
- data/spec/cassette_spec.rb +36 -0
- data/spec/integration/cas/client_spec.rb +0 -3
- data/spec/spec_helper.rb +5 -0
- data/spec/support/controllers/controller_mock.rb +19 -0
- metadata +98 -36
- data/spec/cas_spec.rb +0 -78
@@ -1,27 +1,39 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
2
|
describe Cassette::Authentication do
|
6
3
|
let(:cache) { instance_double(Cassette::Authentication::Cache) }
|
7
4
|
let(:http) { class_double(Cassette) }
|
8
5
|
|
9
|
-
subject do
|
6
|
+
subject(:authentication) do
|
10
7
|
Cassette::Authentication.new(cache: cache, http_client: http)
|
11
8
|
end
|
12
9
|
|
13
10
|
describe '#ticket_user' do
|
11
|
+
subject(:ticket_user) { authentication.ticket_user(ticket) }
|
12
|
+
|
13
|
+
let(:ticket) { 'ticket' }
|
14
|
+
let(:cached_value) { 'cached_value' }
|
15
|
+
let(:service) { 'test-api.example.org' }
|
16
|
+
|
14
17
|
context 'when cached' do
|
15
|
-
|
16
|
-
|
18
|
+
before do
|
19
|
+
allow(cache).to receive(:fetch_authentication)
|
20
|
+
.and_return(cached_value)
|
21
|
+
end
|
22
|
+
|
23
|
+
it { is_expected.to eql(cached_value) }
|
24
|
+
it 'calls Cache#fetch_authentication with ticket and service' do
|
25
|
+
expect(cache).to receive(:fetch_authentication)
|
26
|
+
.with(ticket, service)
|
27
|
+
|
28
|
+
ticket_user
|
29
|
+
end
|
17
30
|
|
18
|
-
|
19
|
-
|
31
|
+
it 'passes a block to Cache#fetch_authentication' do
|
32
|
+
expect(cache).to receive(:fetch_authentication) do |*, &block|
|
20
33
|
expect(block).to be_present
|
21
|
-
cached
|
22
34
|
end
|
23
35
|
|
24
|
-
|
36
|
+
ticket_user
|
25
37
|
end
|
26
38
|
end
|
27
39
|
|
@@ -44,7 +56,7 @@ describe Cassette::Authentication do
|
|
44
56
|
end
|
45
57
|
|
46
58
|
it 'returns nil' do
|
47
|
-
expect(
|
59
|
+
expect(ticket_user).to be_nil
|
48
60
|
end
|
49
61
|
end
|
50
62
|
|
@@ -55,7 +67,7 @@ describe Cassette::Authentication do
|
|
55
67
|
end
|
56
68
|
|
57
69
|
it 'returns an User' do
|
58
|
-
expect(
|
70
|
+
expect(ticket_user).to be_instance_of(Cassette::Authentication::User)
|
59
71
|
end
|
60
72
|
end
|
61
73
|
end
|
data/spec/cassette/cache_spec.rb
CHANGED
@@ -0,0 +1,319 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Cassette::Client do
|
6
|
+
let(:http) { class_double(Cassette) }
|
7
|
+
let(:cache) { instance_double(Cassette::Client::Cache) }
|
8
|
+
let(:options) do
|
9
|
+
{
|
10
|
+
http_client: http,
|
11
|
+
cache: cache,
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:client) do
|
16
|
+
Cassette::Client.new(options)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#health_check' do
|
20
|
+
subject { client.health_check }
|
21
|
+
|
22
|
+
it 'raises any Error' do
|
23
|
+
expect(client).to receive(:st_for).with(anything).and_raise('Failure')
|
24
|
+
|
25
|
+
expect { subject }.to raise_error('Failure')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'tries to generate a ST' do
|
29
|
+
expect(client).to receive(:st_for).with(an_instance_of(String)).and_return('ST-Something')
|
30
|
+
|
31
|
+
expect(subject).to eq 'ST-Something'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#tgt' do
|
36
|
+
subject { client.tgt('user', 'pass', force) }
|
37
|
+
|
38
|
+
context 'http client interactions' do
|
39
|
+
let(:force) { true }
|
40
|
+
let(:response) { Faraday::Response.new }
|
41
|
+
|
42
|
+
before do
|
43
|
+
allow(cache).to receive(:fetch_tgt).and_yield
|
44
|
+
allow(http).to receive(:post) { response }
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'extracts the tgt from the Location header' do
|
48
|
+
tgt = 'TGT-something'
|
49
|
+
allow(response).to receive(:headers).and_return('Location' => "/tickets/#{tgt}")
|
50
|
+
|
51
|
+
expect(subject).to eq tgt
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'posts the username and password' do
|
55
|
+
subject
|
56
|
+
expect(http).to have_received(:post).with(anything, username: 'user', password: 'pass')
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'posts to a /v1/tickets uri' do
|
60
|
+
subject
|
61
|
+
expect(http).to have_received(:post).with(%r{/v1/tickets\z}, instance_of(Hash))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when tgt is not cached' do
|
66
|
+
let(:tgt) { 'TGT-Something-example' }
|
67
|
+
let(:force) { false }
|
68
|
+
|
69
|
+
before do
|
70
|
+
allow(cache).to receive(:fetch_tgt) do |opts, &_block|
|
71
|
+
expect(opts[:force]).to eq false
|
72
|
+
tgt
|
73
|
+
end
|
74
|
+
|
75
|
+
allow(http).to receive(:post)
|
76
|
+
end
|
77
|
+
|
78
|
+
it { is_expected.to eq tgt }
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'with a cached tgt' do
|
82
|
+
let(:tgt) { 'TGT-Something-example' }
|
83
|
+
|
84
|
+
before do
|
85
|
+
allow(cache).to receive(:fetch_tgt).with(hash_including(force: force))
|
86
|
+
.and_return(tgt)
|
87
|
+
|
88
|
+
allow(http).to receive(:post)
|
89
|
+
end
|
90
|
+
|
91
|
+
shared_context 'force control' do
|
92
|
+
it { is_expected.to eq tgt }
|
93
|
+
|
94
|
+
it 'forwards force to the cache' do
|
95
|
+
subject
|
96
|
+
expect(cache).to have_received(:fetch_tgt).with(hash_including(force: force))
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'and no force' do
|
101
|
+
let(:force) { false }
|
102
|
+
|
103
|
+
include_context 'force control'
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'and using the force' do
|
107
|
+
let(:force) { true }
|
108
|
+
|
109
|
+
include_context 'force control'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe '#st' do
|
115
|
+
subject { client.st(tgt_param, service, force) }
|
116
|
+
let(:service) { 'example.org' }
|
117
|
+
let(:tgt) { 'TGT-Example' }
|
118
|
+
let(:st) { 'ST-Something-example' }
|
119
|
+
let(:tgt_param) { tgt }
|
120
|
+
|
121
|
+
shared_context 'http client interactions' do
|
122
|
+
let(:force) { true }
|
123
|
+
let(:response) { Faraday::Response.new }
|
124
|
+
|
125
|
+
before do
|
126
|
+
allow(cache).to receive(:fetch_st).and_yield
|
127
|
+
allow(http).to receive(:post) { response }
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'extracts the tgt from the Location header' do
|
131
|
+
allow(response).to receive(:body) { st }
|
132
|
+
|
133
|
+
expect(subject).to eq st
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'posts the service' do
|
137
|
+
subject
|
138
|
+
|
139
|
+
expect(http).to have_received(:post).with(anything, service: service)
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'posts to the tgt uri' do
|
143
|
+
subject
|
144
|
+
|
145
|
+
expect(http).to have_received(:post).with(%r{/#{tgt}\z}, instance_of(Hash))
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'when tgt is a string' do
|
150
|
+
let(:tgt_param) { tgt }
|
151
|
+
|
152
|
+
it_behaves_like 'http client interactions'
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when tgt is a callable' do
|
156
|
+
let(:tgt_param) { ->{ tgt } }
|
157
|
+
|
158
|
+
it_behaves_like 'http client interactions'
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'cache control' do
|
162
|
+
before do
|
163
|
+
allow(cache).to receive(:fetch_st).with(service, hash_including(force: force))
|
164
|
+
.and_return(st)
|
165
|
+
end
|
166
|
+
|
167
|
+
shared_context 'controlling the force' do
|
168
|
+
it { is_expected.to eq st }
|
169
|
+
|
170
|
+
it 'forwards force to the cache' do
|
171
|
+
subject
|
172
|
+
|
173
|
+
expect(cache).to have_received(:fetch_st).with(service, hash_including(force: force))
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'not using the force' do
|
178
|
+
let(:force) { false }
|
179
|
+
|
180
|
+
include_context 'controlling the force'
|
181
|
+
end
|
182
|
+
|
183
|
+
context 'using the force' do
|
184
|
+
let(:force) { true }
|
185
|
+
|
186
|
+
include_context 'controlling the force'
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe '#st_for' do
|
192
|
+
subject { client.st_for(service) }
|
193
|
+
let(:service) { 'example.org' }
|
194
|
+
let(:cached_tgt) { 'TGT-Something' }
|
195
|
+
let(:tgt) { 'TGT-Something-NEW' }
|
196
|
+
let(:st) { 'ST-For-Something' }
|
197
|
+
|
198
|
+
context 'when tgt and st are not cached' do
|
199
|
+
before do
|
200
|
+
allow(cache).to receive(:fetch_tgt).with(hash_including(force: false)).and_yield
|
201
|
+
allow(cache).to receive(:fetch_st).with(service, hash_including(force: false)).and_yield
|
202
|
+
|
203
|
+
allow(http).to receive(:post)
|
204
|
+
.with(%r{/v1/tickets\z}, username: Cassette.config.username, password: Cassette.config.password)
|
205
|
+
.and_return(tgt_response)
|
206
|
+
|
207
|
+
allow(http).to receive(:post).with(%r{/v1/tickets/#{tgt}\z}, service: service)
|
208
|
+
.and_return(st_response)
|
209
|
+
end
|
210
|
+
|
211
|
+
let(:st_response) { Faraday::Response.new(body: st) }
|
212
|
+
let(:tgt_response) { Faraday::Response.new(response_headers: {'Location' => "/v1/tickets/#{tgt}"}) }
|
213
|
+
|
214
|
+
it 'returns the generated st' do
|
215
|
+
expect(subject).to eq st
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'generates an ST' do
|
219
|
+
subject
|
220
|
+
|
221
|
+
expect(http).to have_received(:post).with(%r{/v1/tickets/#{tgt}\z}, service: service)
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'generates a TGT' do
|
225
|
+
subject
|
226
|
+
|
227
|
+
expect(http).to have_received(:post)
|
228
|
+
.with(%r{/v1/tickets\z}, username: Cassette.config.username, password: Cassette.config.password)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
context 'when tgt is cached but st is not' do
|
233
|
+
before do
|
234
|
+
allow(cache).to receive(:fetch_tgt).with(hash_including(force: false)).and_return(tgt)
|
235
|
+
allow(cache).to receive(:fetch_st).with(service, hash_including(force: false)).and_yield
|
236
|
+
|
237
|
+
allow(http).to receive(:post).with(%r{/v1/tickets/#{tgt}\z}, service: service)
|
238
|
+
.and_return(st_response)
|
239
|
+
end
|
240
|
+
|
241
|
+
let(:st_response) { Faraday::Response.new(body: st) }
|
242
|
+
|
243
|
+
it 'returns the generated st' do
|
244
|
+
expect(subject).to eq st
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'generates an ST' do
|
248
|
+
subject
|
249
|
+
|
250
|
+
expect(http).to have_received(:post).with(%r{/v1/tickets/#{tgt}\z}, service: service)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
context 'when st is cached' do
|
255
|
+
before do
|
256
|
+
allow(cache).to receive(:fetch_st).with(service, hash_including(force: false)).and_return(st)
|
257
|
+
end
|
258
|
+
|
259
|
+
it 'returns the cached value' do
|
260
|
+
expect(subject).to eq st
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
context 'when tgt is expired' do
|
265
|
+
before do
|
266
|
+
allow(cache).to receive(:fetch_tgt).with(hash_including(force: false)).and_return(cached_tgt)
|
267
|
+
allow(cache).to receive(:fetch_tgt).with(hash_including(force: true)).and_yield
|
268
|
+
allow(cache).to receive(:fetch_st).and_yield
|
269
|
+
|
270
|
+
allow(http).to receive(:post).with(%r{/v1/tickets/#{cached_tgt}\z}, service: service)
|
271
|
+
.and_raise(Cassette::Errors::NotFound)
|
272
|
+
|
273
|
+
allow(http).to receive(:post)
|
274
|
+
.with(%r{/v1/tickets\z}, username: Cassette.config.username, password: Cassette.config.password)
|
275
|
+
.and_return(tgt_response)
|
276
|
+
|
277
|
+
allow(http).to receive(:post).with(%r{/v1/tickets/#{tgt}\z}, service: service)
|
278
|
+
.and_return(st_response)
|
279
|
+
end
|
280
|
+
|
281
|
+
let(:tgt_response) { Faraday::Response.new(response_headers: {'Location' => "/v1/tickets/#{tgt}"}) }
|
282
|
+
let(:st_response) { Faraday::Response.new(body: st) }
|
283
|
+
|
284
|
+
it 'calls #fetch_st twice' do
|
285
|
+
subject
|
286
|
+
|
287
|
+
expect(cache).to have_received(:fetch_st).twice
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'calls #fetch_tgt without forcing' do
|
291
|
+
subject
|
292
|
+
|
293
|
+
expect(cache).to have_received(:fetch_tgt).with(force: false)
|
294
|
+
end
|
295
|
+
|
296
|
+
it 'calls #fetch_tgt forcing' do
|
297
|
+
subject
|
298
|
+
|
299
|
+
expect(cache).to have_received(:fetch_tgt).with(force: true)
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'tries to generate a ST with the expired TGT' do
|
303
|
+
subject
|
304
|
+
|
305
|
+
expect(http).to have_received(:post).with(%r{/v1/tickets/#{cached_tgt}\z}, service: service)
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'retries to generate a ST with the new TGT' do
|
309
|
+
subject
|
310
|
+
|
311
|
+
expect(http).to have_received(:post).with(%r{/v1/tickets/#{tgt}\z}, service: service)
|
312
|
+
end
|
313
|
+
|
314
|
+
it 'returns a brand new tgt' do
|
315
|
+
expect(subject).to eq st
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
describe Cassette::Http::ParsedResponse do
|
2
|
+
subject(:parsed_response) { described_class.new(xml_response) }
|
3
|
+
|
4
|
+
let(:xml_response) { fixture('cas/success.xml') }
|
5
|
+
|
6
|
+
let(:hash_response) do
|
7
|
+
{
|
8
|
+
"serviceResponse" => {
|
9
|
+
"authenticationSuccess" => {
|
10
|
+
"user"=> {
|
11
|
+
"__content__" => "test-user"
|
12
|
+
},
|
13
|
+
"attributes" => {
|
14
|
+
"authorities" => {
|
15
|
+
"__content__" => "[CUPOM, AUDITING,]"
|
16
|
+
},
|
17
|
+
"cn" => {
|
18
|
+
"__content__" => "Test System"
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
it { is_expected.to eq(hash_response) }
|
27
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
describe Cassette::Http::Request do
|
2
|
+
subject(:request) { described_class }
|
3
|
+
|
4
|
+
describe '.post' do
|
5
|
+
subject(:post) { request.post(uri, payload) }
|
6
|
+
|
7
|
+
let(:uri) { 'http://example.org/' }
|
8
|
+
let(:payload) { { ping: :pong } }
|
9
|
+
let(:response) do
|
10
|
+
{
|
11
|
+
headers: { 'Content-Type' => 'application/json' },
|
12
|
+
body: { ok: :true }.to_json,
|
13
|
+
status: 200
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
before { stub_request(:post, uri).to_return(response) }
|
18
|
+
|
19
|
+
it 'performs a http post request with the proper params'do
|
20
|
+
post
|
21
|
+
|
22
|
+
expect(a_request(:post, uri).with(body: 'ping=pong')).to have_been_made
|
23
|
+
end
|
24
|
+
|
25
|
+
it do
|
26
|
+
is_expected.to have_attributes(
|
27
|
+
headers: { 'Content-Type' => 'application/json' },
|
28
|
+
body: '{"ok":"true"}',
|
29
|
+
status: 200
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when response has an error status code' do
|
34
|
+
let(:response) { { status: 500 } }
|
35
|
+
|
36
|
+
it 'raises an exception' do
|
37
|
+
expect { post }.to raise_error(Cassette::Errors::InternalServerError)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
describe Cassette::Http::TicketResponse do
|
2
|
+
subject(:ticket_response) { described_class.new(xml_response) }
|
3
|
+
|
4
|
+
let(:xml_response) { fixture('cas/success.xml') }
|
5
|
+
|
6
|
+
describe '#login' do
|
7
|
+
subject(:login) { ticket_response.login }
|
8
|
+
|
9
|
+
it { is_expected.to eq('test-user') }
|
10
|
+
|
11
|
+
context "when response isn't successful" do
|
12
|
+
let(:xml_response) { fixture('cas/fail.xml') }
|
13
|
+
|
14
|
+
it { is_expected.to be_nil }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#name' do
|
19
|
+
subject(:name) { ticket_response.name }
|
20
|
+
|
21
|
+
it { is_expected.to eq('Test System') }
|
22
|
+
|
23
|
+
context "when response isn't successful" do
|
24
|
+
let(:xml_response) { fixture('cas/fail.xml') }
|
25
|
+
|
26
|
+
it { is_expected.to be_nil }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#authorities' do
|
31
|
+
subject(:authorities) { ticket_response.authorities }
|
32
|
+
|
33
|
+
it { is_expected.to eq('[CUPOM, AUDITING,]') }
|
34
|
+
|
35
|
+
context "when response isn't successful" do
|
36
|
+
let(:xml_response) { fixture('cas/fail.xml') }
|
37
|
+
|
38
|
+
it { is_expected.to be_nil }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Cassette::Rubycas::RoutingConstraint do
|
6
|
+
describe '#matches?' do
|
7
|
+
let(:request) do
|
8
|
+
OpenStruct.new(session: session)
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:user) { instance_double(Cassette::Authentication::User) }
|
12
|
+
let(:constraint) { described_class.new(role, options) }
|
13
|
+
|
14
|
+
subject { constraint.matches?(request) }
|
15
|
+
|
16
|
+
before do
|
17
|
+
allow(constraint).to receive(:from_session).with(session).and_return(user)
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:session) do
|
21
|
+
{
|
22
|
+
cas_user: 'test.user',
|
23
|
+
cas_extra_attributes: {
|
24
|
+
cn: 'test user',
|
25
|
+
email: 'test.user@example.org'
|
26
|
+
}
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'with no options' do
|
31
|
+
let(:role) { :admin }
|
32
|
+
let(:options) { {} }
|
33
|
+
let(:has_role) { true }
|
34
|
+
|
35
|
+
before do
|
36
|
+
allow(user).to receive(:has_role?).with(role).and_return(has_role)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'checks the User role' do
|
40
|
+
subject
|
41
|
+
expect(user).to have_received(:has_role?).with(role)
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when user has the role' do
|
45
|
+
let(:has_role) { true }
|
46
|
+
|
47
|
+
it { is_expected.to eq(true) }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when user does not have the role' do
|
51
|
+
let(:has_role) { false }
|
52
|
+
|
53
|
+
it { is_expected.to eq(false) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when options[:raw] = true' do
|
58
|
+
let(:role) { 'API_ADMIN' }
|
59
|
+
let(:options) { { raw: true } }
|
60
|
+
let(:has_role) { true }
|
61
|
+
|
62
|
+
before do
|
63
|
+
allow(user).to receive(:has_raw_role?).with(role).and_return(has_role)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'checks the User role' do
|
67
|
+
subject
|
68
|
+
expect(user).to have_received(:has_raw_role?).with(role)
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when user has the role' do
|
72
|
+
let(:has_role) { true }
|
73
|
+
|
74
|
+
it { is_expected.to eq(true) }
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'when user does not have the role' do
|
78
|
+
let(:has_role) { false }
|
79
|
+
|
80
|
+
it { is_expected.to eq(false) }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
describe Cassette do
|
4
|
+
def keeping_logger(&block)
|
5
|
+
original_logger = Cassette.logger
|
6
|
+
block.call
|
7
|
+
Cassette.logger = original_logger
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '.logger' do
|
11
|
+
it 'returns a default instance' do
|
12
|
+
expect(Cassette.logger).not_to be_nil
|
13
|
+
expect(Cassette.logger.is_a?(Logger)).to eql(true)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns rails logger when Rails is available' do
|
17
|
+
keeping_logger do
|
18
|
+
Cassette.logger = nil
|
19
|
+
rails = double('Rails')
|
20
|
+
expect(rails).to receive(:logger).and_return(rails).at_least(:once)
|
21
|
+
stub_const('Rails', rails)
|
22
|
+
expect(Cassette.logger).to eql(rails)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '.logger=' do
|
28
|
+
let(:logger) { Logger.new(STDOUT) }
|
29
|
+
it 'defines the logger instance' do
|
30
|
+
keeping_logger do
|
31
|
+
Cassette.logger = logger
|
32
|
+
expect(Cassette.logger).to eq(logger)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
4
|
+
|
5
|
+
def ControllerMock(*mods)
|
6
|
+
mods.inject(Class.new(ControllerMock)) do |c, mod|
|
7
|
+
c.send(:include, mod)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class ControllerMock
|
12
|
+
attr_accessor :params, :request, :current_user
|
13
|
+
def self.before_filter(*); end
|
14
|
+
|
15
|
+
def initialize(params = {}, headers = {})
|
16
|
+
self.params = params.with_indifferent_access
|
17
|
+
self.request = OpenStruct.new(headers: headers.with_indifferent_access)
|
18
|
+
end
|
19
|
+
end
|