diff --git a/lib/google/apis/core/upload.rb b/lib/google/apis/core/upload.rb index af4007433..723dbc94f 100644 --- a/lib/google/apis/core/upload.rb +++ b/lib/google/apis/core/upload.rb @@ -178,7 +178,6 @@ module Google def process_response(status, header, body) @offset = Integer(header[BYTES_RECEIVED_HEADER]) if header.key?(BYTES_RECEIVED_HEADER) @upload_url = header[UPLOAD_URL_HEADER] if header.key?(UPLOAD_URL_HEADER) - upload_status = header[UPLOAD_STATUS_HEADER] logger.debug { sprintf('Upload status %s', upload_status) } if upload_status == STATUS_ACTIVE @@ -254,12 +253,16 @@ module Google # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification # @raise [Google::Apis::AuthorizationError] Authorization is required def execute_once(client, &block) - if @state == :start + case @state + when :start response = send_start_command(client) - else + result = process_response(response.status_code, response.header, response.body) + when :active response = send_query_command(client) + result = process_response(response.status_code, response.header, response.body) + when :cancelled, :final + error(@last_error, rethrow: true, &block) end - result = process_response(response.status_code, response.header, response.body) if @state == :active response = send_upload_command(client) result = process_response(response.status_code, response.header, response.body) @@ -267,6 +270,10 @@ module Google success(result, &block) if @state == :final rescue => e + # Some APIs like Youtube generate non-retriable 401 errors and mark + # the upload as finalized. Save the error just in case we get + # retried. + @last_error = e error(e, rethrow: true, &block) end end diff --git a/spec/google/apis/core/upload_spec.rb b/spec/google/apis/core/upload_spec.rb index b6265a8c3..e18c60119 100644 --- a/spec/google/apis/core/upload_spec.rb +++ b/spec/google/apis/core/upload_spec.rb @@ -49,7 +49,7 @@ RSpec.describe Google::Apis::Core::UploadIO do end it 'should setup length of the stream' do - upload_io = Google::Apis::Core::UploadIO.from_file(file) + upload_io = Google::Apis::Core::UploadIO.from_file(file) expect(upload_io.length).to eq File.size(file) end @@ -60,9 +60,9 @@ RSpec.describe Google::Apis::Core::UploadIO do context 'with i/o stream' do let(:io) { StringIO.new 'Hello google' } - + it 'should setup default content-type' do - upload_io = Google::Apis::Core::UploadIO.from_io(io) + upload_io = Google::Apis::Core::UploadIO.from_io(io) expect(upload_io.content_type).to eql Google::Apis::Core::UploadIO::OCTET_STREAM_CONTENT_TYPE end @@ -72,7 +72,7 @@ RSpec.describe Google::Apis::Core::UploadIO do end it 'should setup length of the stream' do - upload_io = Google::Apis::Core::UploadIO.from_io(io) + upload_io = Google::Apis::Core::UploadIO.from_io(io) expect(upload_io.length).to eq 'Hello google'.length end end @@ -244,6 +244,17 @@ RSpec.describe Google::Apis::Core::ResumableUploadCommand do end end + context 'with non-retriable authorization error on start' do + before(:example) do + stub_request(:post, 'https://www.googleapis.com/zoo/animals') + .to_return(status: [401, 'unauthorized'], headers: { 'X-Goog-Upload-Status' => 'final' }, body: %(unauthorized)) + end + + it 'should propagate the original error' do + expect { command.execute(client) }.to raise_error Google::Apis::AuthorizationError + end + end + context 'with interruption' do before(:example) do stub_request(:post, 'https://www.googleapis.com/zoo/animals')