Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion lib/bundler/fetcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@ def fetch_spec(spec)
elsif cached_spec_path = gemspec_cached_path(spec_file_name)
Bundler.load_gemspec(cached_spec_path)
else
Bundler.safe_load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body)
# Retried like `specs_with_retry`, which fetches the full index.
body = Bundler::Retry.new("fetcher", FAIL_ERRORS).attempts do
downloader.fetch(uri).body
end
Bundler.safe_load_marshal Bundler.rubygems.inflate(body)
end
raise MarshalError, "is #{spec.inspect}" unless spec.is_a?(Gem::Specification)
spec
Expand Down
27 changes: 27 additions & 0 deletions spec/bundler/fetcher_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,33 @@ def configured_connection
end
end

context "when the download fails transiently" do
let(:spec) { Gem::Specification.new(name, version) }
let(:downloaded_data) { Zlib::Deflate.deflate(Marshal.dump(spec)) }

it "retries the download and returns the spec" do
expect(Bundler::Fetcher::Downloader).to receive(:new).and_return(downloader)
expect(downloader).to receive(:fetch).twice do
@attempts = (@attempts || 0) + 1
raise Bundler::HTTPError, "transient network failure" if @attempts == 1
body
end

result = fetcher.fetch_spec([name, version, platform])
expect(result).to eq(spec)
end

it "does not retry an error that bypasses retries" do
expect(Bundler::Fetcher::Downloader).to receive(:new).and_return(downloader)
expect(downloader).to receive(:fetch).once.and_raise(
Bundler::Fetcher::AuthenticationRequiredError.new("http://example.org")
)

expect { fetcher.fetch_spec([name, version, platform]) }.
to raise_error(Bundler::Fetcher::AuthenticationRequiredError)
end
end

context "when attempting to load an unexpected class" do
let(:downloaded_data) { Zlib::Deflate.deflate(Marshal.dump(3)) }

Expand Down