Skip to content

Commit d9bd299

Browse files
Removed VCR from libriaries request specs made some other changes to satisfy rubocop and get full branch coverage
1 parent 18b97da commit d9bd299

File tree

10 files changed

+211
-408
lines changed

10 files changed

+211
-408
lines changed

lib/berkeley_library/location/world_cat/oclc_auth.rb

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,35 @@ def initialize
1717
end
1818

1919
def fetch_token
20-
url = oclc_token_url
20+
response = http_client.request(token_request)
21+
parse_token_response(response)
22+
end
2123

22-
http = Net::HTTP.new(url.host, url.port)
23-
http.use_ssl = url.scheme == 'https'
24+
def http_client
25+
url = oclc_token_url
2426

25-
# Skip SSL verification ONLY when recording new VCR cassettes
26-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if ENV['RE_RECORD_VCR'] == 'true'
27+
Net::HTTP.new(url.host, url.port).tap do |http|
28+
http.use_ssl = url.scheme == 'https'
29+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if skip_ssl_verification?
30+
end
31+
end
2732

28-
request = Net::HTTP::Post.new(url.request_uri)
29-
request.basic_auth(Config.api_key, Config.api_secret)
30-
request['Accept'] = 'application/json'
31-
response = http.request(request)
33+
def token_request
34+
Net::HTTP::Post.new(oclc_token_url.request_uri).tap do |request|
35+
request.basic_auth(Config.api_key, Config.api_secret)
36+
request['Accept'] = 'application/json'
37+
end
38+
end
3239

40+
def parse_token_response(response)
3341
JSON.parse(response.body, symbolize_names: true)
3442
end
3543

44+
# Skip SSL verification ONLY when recording new VCR cassettes
45+
def skip_ssl_verification?
46+
ENV['RE_RECORD_VCR'] == 'true'
47+
end
48+
3649
def oclc_token_url
3750
URI.parse("#{Config.token_uri}?#{URI.encode_www_form(token_params)}")
3851
end

spec/berkeley_library/location/world_cat/libraries_request_spec.rb

Lines changed: 86 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,23 @@ module WorldCat
77
let(:wc_api_key) { '2lo55pdh7moyfodeo4gwgms0on65x31ghv0g6yg87ffwaljsdw' }
88
let(:wc_api_secret) { 'totallyfakesecret' }
99

10+
before do
11+
auth = instance_double(
12+
BerkeleyLibrary::Location::WorldCat::OCLCAuth,
13+
access_token: 'fake-access-token'
14+
)
15+
16+
allow(BerkeleyLibrary::Location::WorldCat::OCLCAuth)
17+
.to receive(:instance)
18+
.and_return(auth)
19+
end
20+
1021
after do
1122
BerkeleyLibrary::Location::WorldCat::OCLCAuth
1223
.instance_variable_set(:@singleton__instance__, nil)
1324
end
1425

15-
1626
describe :new do
17-
before do
18-
auth = instance_double(
19-
BerkeleyLibrary::Location::WorldCat::OCLCAuth,
20-
access_token: 'fake-access-token'
21-
)
22-
23-
allow(BerkeleyLibrary::Location::WorldCat::OCLCAuth)
24-
.to receive(:new)
25-
.and_return(auth)
26-
end
27-
2827
describe :oclc_number do
2928
it 'accepts a valid OCLC number' do
3029
q = LibrariesRequest.new(oclc_number)
@@ -78,17 +77,6 @@ module WorldCat
7877
end
7978

8079
describe :uri do
81-
before do
82-
auth = instance_double(
83-
BerkeleyLibrary::Location::WorldCat::OCLCAuth,
84-
access_token: 'fake-access-token'
85-
)
86-
87-
allow(BerkeleyLibrary::Location::WorldCat::OCLCAuth)
88-
.to receive(:new)
89-
.and_return(auth)
90-
end
91-
9280
it 'returns the URI for the specified OCLC number' do
9381
uri_expected = URI.parse("#{wc_base_url}bibs-holdings")
9482
uri_actual = LibrariesRequest.new(oclc_number).uri
@@ -101,21 +89,54 @@ module WorldCat
10189
holdings_expected = %w[CUI CUY MERUC ZAP]
10290
req = LibrariesRequest.new(oclc_number)
10391

104-
VCR.use_cassette('libraries_request/execute_holdings_1') do
105-
holdings_actual = req.execute
106-
expect(holdings_actual).to contain_exactly(*holdings_expected)
107-
end
92+
allow(BerkeleyLibrary::Util::URIs).to receive(:get).and_return(
93+
{
94+
'briefRecords' => [
95+
{
96+
'institutionHolding' => {
97+
'briefHoldings' => [
98+
{ 'oclcSymbol' => 'CUI' },
99+
{ 'oclcSymbol' => 'CUY' }
100+
]
101+
}
102+
},
103+
{
104+
'institutionHolding' => {
105+
'briefHoldings' => [
106+
{ 'oclcSymbol' => 'MERUC' },
107+
{ 'oclcSymbol' => 'ZAP' }
108+
]
109+
}
110+
}
111+
]
112+
}
113+
)
114+
115+
holdings_actual = req.execute
116+
expect(holdings_actual).to contain_exactly(*holdings_expected)
108117
end
109118

110119
it 'returns a specified subset of holdings' do
111120
holdings_expected = %w[ZAP]
112121
symbols = Symbols::SLF
113122
req = LibrariesRequest.new(oclc_number, symbols:)
114123

115-
VCR.use_cassette('libraries_request/execute_holdings_2') do
116-
holdings_actual = req.execute
117-
expect(holdings_actual).to contain_exactly(*holdings_expected)
118-
end
124+
allow(BerkeleyLibrary::Util::URIs).to receive(:get).and_return(
125+
{
126+
'briefRecords' => [
127+
{
128+
'institutionHolding' => {
129+
'briefHoldings' => [
130+
{ 'oclcSymbol' => 'ZAP' }
131+
]
132+
}
133+
}
134+
]
135+
}
136+
)
137+
138+
holdings_actual = req.execute
139+
expect(holdings_actual).to contain_exactly(*holdings_expected)
119140
end
120141

121142
# NOTE: WorldCat *shouldn't* return holdings information for any
@@ -125,21 +146,47 @@ module WorldCat
125146
symbols = Symbols::UC
126147
req = LibrariesRequest.new(oclc_number, symbols:)
127148

128-
VCR.use_cassette('libraries_request/execute_holdings_3') do
129-
holdings_actual = req.execute
130-
expect(holdings_actual).to contain_exactly(*holdings_expected)
131-
end
149+
allow(BerkeleyLibrary::Util::URIs).to receive(:get).and_return(
150+
{
151+
'briefRecords' => [
152+
{
153+
'institutionHolding' => {
154+
'briefHoldings' => [
155+
{ 'oclcSymbol' => 'CUI' },
156+
{ 'oclcSymbol' => 'CUY' }
157+
]
158+
}
159+
},
160+
{
161+
'institutionHolding' => {
162+
'briefHoldings' => [
163+
{ 'oclcSymbol' => 'MERUC' }
164+
]
165+
}
166+
}
167+
]
168+
}
169+
)
170+
171+
holdings_actual = req.execute
172+
expect(holdings_actual).to contain_exactly(*holdings_expected)
132173
end
133174

134175
it 'returns an empty list when no holdings are found' do
135176
oclc_number = '10045193'
136177
symbols = Symbols::SLF
137178
req = LibrariesRequest.new(oclc_number, symbols:)
138179

139-
VCR.use_cassette('libraries_request/execute_holdings_4') do
140-
holdings_actual = req.execute
141-
expect(holdings_actual).to be_empty
142-
end
180+
# Stub a response with empty holdings
181+
stub_request(:get, /bibs-holdings/)
182+
.to_return(
183+
status: 200,
184+
headers: { 'Content-Type' => 'application/json' },
185+
body: { holdings: [] }.to_json
186+
)
187+
188+
holdings_actual = req.execute
189+
expect(holdings_actual).to be_empty
143190
end
144191
end
145192
end

spec/berkeley_library/location/world_cat/oclc_auth_spec.rb

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,83 @@ module WorldCat
3636
end
3737
end
3838

39-
describe '#token_expired?' do
39+
describe '#access_token' do
4040
subject(:oclc_auth) { described_class.instance }
4141

42-
it 'returns true if @token is nil' do
42+
after do
43+
# Reset token so other tests aren't affected
4344
oclc_auth.instance_variable_set(:@token, nil)
44-
expect(oclc_auth.send(:token_expired?)).to be true
45+
end
46+
47+
it 'returns the current token if not expired' do
48+
oclc_auth.instance_variable_set(:@token, { access_token: 'existing-token', expires_at: (Time.now + 60).to_s })
49+
expect(oclc_auth.access_token).to eq('existing-token')
50+
end
51+
52+
it 'fetches a new token if expired' do
53+
allow(oclc_auth).to receive(:fetch_token).and_return({ access_token: 'new-token', expires_at: (Time.now + 3600).to_s })
54+
oclc_auth.instance_variable_set(:@token, { access_token: 'old-token', expires_at: (Time.now - 60).to_s })
55+
expect(oclc_auth.access_token).to eq('new-token')
56+
end
57+
58+
describe '#token_expired?' do
59+
subject(:oclc_auth) { described_class.instance }
60+
61+
it 'returns true if @token is nil' do
62+
oclc_auth.instance_variable_set(:@token, nil)
63+
expect(oclc_auth.send(:token_expired?)).to be true
64+
end
65+
66+
it 'returns true if token is expired' do
67+
oclc_auth.instance_variable_set(:@token, { access_token: 'x', expires_at: (Time.now - 1).to_s })
68+
expect(oclc_auth.send(:token_expired?)).to be true
69+
end
70+
71+
it 'returns false if token is still valid' do
72+
oclc_auth.instance_variable_set(:@token, { access_token: 'x', expires_at: (Time.now + 60).to_s })
73+
expect(oclc_auth.send(:token_expired?)).to be false
74+
end
75+
end
76+
end
77+
78+
describe '#skip_ssl_verification?' do
79+
subject(:oclc_auth) { described_class.instance }
80+
81+
it 'returns true when RE_RECORD_VCR=true' do
82+
allow(ENV).to receive(:[]).with('RE_RECORD_VCR').and_return('true')
83+
expect(oclc_auth.send(:skip_ssl_verification?)).to be true
84+
end
85+
end
86+
87+
describe '#fetch_token (SSL verification false branch)' do
88+
subject(:oclc_auth) { described_class.instance }
89+
90+
let(:url) { URI('https://example.test/token') }
91+
let(:http) { instance_double(Net::HTTP) }
92+
let(:response) do
93+
instance_double(Net::HTTPResponse, body: '{"access_token":"abc"}')
94+
end
95+
96+
before do
97+
allow(oclc_auth).to receive(:skip_ssl_verification?).and_return(false)
98+
allow(oclc_auth).to receive(:oclc_token_url).and_return(url)
99+
100+
allow(Net::HTTP).to receive(:new).and_return(http)
101+
allow(http).to receive(:use_ssl=).with(true)
102+
allow(http).to receive(:request).and_return(response)
103+
104+
allow(Config).to receive(:api_key).and_return('key')
105+
allow(Config).to receive(:api_secret).and_return('secret')
106+
end
107+
108+
after do
109+
oclc_auth.instance_variable_set(:@token, nil)
110+
end
111+
112+
it 'does not disable SSL verification when skip_ssl_verification? is false' do
113+
expect(http).not_to receive(:verify_mode=)
114+
115+
oclc_auth.send(:fetch_token)
45116
end
46117
end
47118
end

spec/cassettes/libraries_request/execute_holdings_1.yml

Lines changed: 0 additions & 82 deletions
This file was deleted.

0 commit comments

Comments
 (0)