Skip to content

Commit 17092bb

Browse files
committed
Unit test updates + ensure auth retry only done once per execute
1 parent 2bed074 commit 17092bb

File tree

2 files changed

+92
-11
lines changed

2 files changed

+92
-11
lines changed

lib/google/api_client.rb

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ def initialize(options={})
109109
self.key = options[:key]
110110
self.user_ip = options[:user_ip]
111111
self.retries = options.fetch(:retries) { 0 }
112+
self.expired_auth_retry = options.fetch(:expired_auth_retry) { true }
112113
@discovery_uris = {}
113114
@discovery_documents = {}
114115
@discovered_apis = {}
@@ -239,6 +240,13 @@ def authorization=(new_authorization)
239240
# Number of retries
240241
attr_accessor :retries
241242

243+
##
244+
# Whether or not an expired auth token should be re-acquired
245+
# (and the operation retried) regardless of retries setting
246+
# @return [Boolean]
247+
# Auto retry on auth expiry
248+
attr_accessor :expired_auth_retry
249+
242250
##
243251
# Returns the URI for the directory document.
244252
#
@@ -593,16 +601,20 @@ def execute!(*params)
593601
request.authorization = options[:authorization] || self.authorization unless options[:authenticated] == false
594602

595603
tries = 1 + (options[:retries] || self.retries)
604+
attempt = 0
596605

597606
Retriable.retriable :tries => tries,
598607
:on => [TransmissionError],
608+
:on_retry => client_error_handler,
599609
:interval => lambda {|attempts| (2 ** attempts) + rand} do
610+
attempt += 1
611+
600612
# This 2nd level retriable only catches auth errors, and supports 1 retry, which allows
601613
# auth to be re-attempted without having to retry all sorts of other failures like
602614
# NotFound, etc
603-
Retriable.retriable :tries => 2,
615+
Retriable.retriable :tries => ((expired_auth_retry || tries > 1) && attempt == 1) ? 2 : 1,
604616
:on => [AuthorizationError],
605-
:on_retry => client_error_handler(request.authorization),
617+
:on_retry => authorization_error_handler(request.authorization),
606618
:interval => lambda {|attempts| (2 ** attempts) + rand} do
607619
result = request.send(connection, true)
608620

@@ -671,18 +683,17 @@ def resolve_uri(template, mapping={})
671683

672684

673685
##
674-
# Returns on proc for special processing of retries as not all client errors
675-
# are recoverable. Only 401s should be retried and only if the credentials
676-
# are refreshable
686+
# Returns on proc for special processing of retries for authorization errors
687+
# Only 401s should be retried and only if the credentials are refreshable
677688
#
678689
# @param [#fetch_access_token!] authorization
679690
# OAuth 2 credentials
680-
# @return [Proc]
681-
def client_error_handler(authorization)
691+
# @return [Proc]
692+
def authorization_error_handler(authorization)
682693
can_refresh = authorization.respond_to?(:refresh_token) && auto_refresh_token
683694
Proc.new do |exception, tries|
684-
next unless exception.kind_of?(ClientError)
685-
if exception.result.status == 401 && can_refresh && tries == 1
695+
next unless exception.kind_of?(AuthorizationError)
696+
if can_refresh
686697
begin
687698
logger.debug("Attempting refresh of access token & retry of request")
688699
authorization.fetch_access_token!
@@ -694,6 +705,17 @@ def client_error_handler(authorization)
694705
end
695706
end
696707

708+
##
709+
# Returns on proc for special processing of retries as not all client errors
710+
# are recoverable. Only 401s should be retried (via authorization_error_handler)
711+
#
712+
# @return [Proc]
713+
def client_error_handler
714+
Proc.new do |exception, tries|
715+
raise exception if exception.kind_of?(ClientError)
716+
end
717+
end
718+
697719
end
698720

699721
end

spec/google/api_client_spec.rb

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@
194194
)
195195
end
196196

197-
it 'should refresh tokens on 401 tokens' do
197+
it 'should refresh tokens on 401 errors' do
198198
client.authorization.access_token = '12345'
199199
expect(client.authorization).to receive(:fetch_access_token!)
200200

@@ -283,5 +283,64 @@
283283
count.should == 3
284284
end
285285

286-
end
286+
end
287+
288+
describe 'when retries disabled and expired_auth_retry on (default)' do
289+
before do
290+
client.retries = 0
291+
end
292+
293+
after do
294+
@connection.verify
295+
end
296+
297+
it 'should refresh tokens on 401 errors' do
298+
client.authorization.access_token = '12345'
299+
expect(client.authorization).to receive(:fetch_access_token!)
300+
301+
@connection = stub_connection do |stub|
302+
stub.get('/foo') do |env|
303+
[401, {}, '{}']
304+
end
305+
stub.get('/foo') do |env|
306+
[200, {}, '{}']
307+
end
308+
end
309+
310+
client.execute(
311+
:uri => 'https://www.gogole.com/foo',
312+
:connection => @connection
313+
)
314+
end
315+
316+
end
317+
318+
describe 'when retries disabled and expired_auth_retry off' do
319+
before do
320+
client.retries = 0
321+
client.expired_auth_retry = false
322+
end
323+
324+
it 'should not refresh tokens on 401 errors' do
325+
client.authorization.access_token = '12345'
326+
expect(client.authorization).not_to receive(:fetch_access_token!)
327+
328+
@connection = stub_connection do |stub|
329+
stub.get('/foo') do |env|
330+
[401, {}, '{}']
331+
end
332+
stub.get('/foo') do |env|
333+
[200, {}, '{}']
334+
end
335+
end
336+
337+
resp = client.execute(
338+
:uri => 'https://www.gogole.com/foo',
339+
:connection => @connection
340+
)
341+
342+
resp.response.status.should == 401
343+
end
344+
345+
end
287346
end

0 commit comments

Comments
 (0)