223 lines
6.1 KiB
Ruby
223 lines
6.1 KiB
Ruby
require 'spec_helper'
|
|
|
|
describe Projects::LfsPointers::LfsDownloadService do
|
|
let(:project) { create(:project) }
|
|
let(:lfs_content) { SecureRandom.random_bytes(10) }
|
|
let(:oid) { Digest::SHA256.hexdigest(lfs_content) }
|
|
let(:download_link) { "http://gitlab.com/#{oid}" }
|
|
let(:size) { lfs_content.size }
|
|
let(:lfs_object) { LfsDownloadObject.new(oid: oid, size: size, link: download_link) }
|
|
let(:local_request_setting) { false }
|
|
|
|
subject { described_class.new(project, lfs_object) }
|
|
|
|
before do
|
|
ApplicationSetting.create_from_defaults
|
|
|
|
stub_application_setting(allow_local_requests_from_hooks_and_services: local_request_setting)
|
|
allow(project).to receive(:lfs_enabled?).and_return(true)
|
|
end
|
|
|
|
shared_examples 'lfs temporal file is removed' do
|
|
it do
|
|
subject.execute
|
|
|
|
expect(File.exist?(subject.send(:tmp_filename))).to be false
|
|
end
|
|
end
|
|
|
|
shared_examples 'no lfs object is created' do
|
|
it do
|
|
expect { subject.execute }.not_to change { LfsObject.count }
|
|
end
|
|
|
|
it 'returns error result' do
|
|
expect(subject.execute[:status]).to eq :error
|
|
end
|
|
|
|
it 'an error is logged' do
|
|
expect(subject).to receive(:log_error)
|
|
|
|
subject.execute
|
|
end
|
|
|
|
it_behaves_like 'lfs temporal file is removed'
|
|
end
|
|
|
|
shared_examples 'lfs object is created' do
|
|
it do
|
|
expect(subject).to receive(:download_and_save_file!).and_call_original
|
|
|
|
expect { subject.execute }.to change { LfsObject.count }.by(1)
|
|
end
|
|
|
|
it 'returns success result' do
|
|
expect(subject.execute[:status]).to eq :success
|
|
end
|
|
|
|
it_behaves_like 'lfs temporal file is removed'
|
|
end
|
|
|
|
describe '#execute' do
|
|
context 'when file download succeeds' do
|
|
before do
|
|
WebMock.stub_request(:get, download_link).to_return(body: lfs_content)
|
|
end
|
|
|
|
it_behaves_like 'lfs object is created'
|
|
|
|
it 'has the same oid' do
|
|
subject.execute
|
|
|
|
expect(LfsObject.first.oid).to eq oid
|
|
end
|
|
|
|
it 'has the same size' do
|
|
subject.execute
|
|
|
|
expect(LfsObject.first.size).to eq size
|
|
end
|
|
|
|
it 'stores the content' do
|
|
subject.execute
|
|
|
|
expect(File.binread(LfsObject.first.file.file.file)).to eq lfs_content
|
|
end
|
|
end
|
|
|
|
context 'when file download fails' do
|
|
before do
|
|
allow(Gitlab::HTTP).to receive(:get).and_return(code: 500, 'success?' => false)
|
|
end
|
|
|
|
it_behaves_like 'no lfs object is created'
|
|
|
|
it 'raise StandardError exception' do
|
|
expect(subject).to receive(:download_and_save_file!).and_raise(StandardError)
|
|
|
|
subject.execute
|
|
end
|
|
end
|
|
|
|
context 'when downloaded lfs file has a different size' do
|
|
let(:size) { 1 }
|
|
|
|
before do
|
|
WebMock.stub_request(:get, download_link).to_return(body: lfs_content)
|
|
end
|
|
|
|
it_behaves_like 'no lfs object is created'
|
|
|
|
it 'raise SizeError exception' do
|
|
expect(subject).to receive(:download_and_save_file!).and_raise(described_class::SizeError)
|
|
|
|
subject.execute
|
|
end
|
|
end
|
|
|
|
context 'when downloaded lfs file has a different oid' do
|
|
before do
|
|
WebMock.stub_request(:get, download_link).to_return(body: lfs_content)
|
|
allow_any_instance_of(Digest::SHA256).to receive(:hexdigest).and_return('foobar')
|
|
end
|
|
|
|
it_behaves_like 'no lfs object is created'
|
|
|
|
it 'raise OidError exception' do
|
|
expect(subject).to receive(:download_and_save_file!).and_raise(described_class::OidError)
|
|
|
|
subject.execute
|
|
end
|
|
end
|
|
|
|
context 'when credentials present' do
|
|
let(:download_link_with_credentials) { "http://user:password@gitlab.com/#{oid}" }
|
|
let(:lfs_object) { LfsDownloadObject.new(oid: oid, size: size, link: download_link_with_credentials) }
|
|
|
|
before do
|
|
WebMock.stub_request(:get, download_link).with(headers: { 'Authorization' => 'Basic dXNlcjpwYXNzd29yZA==' }).to_return(body: lfs_content)
|
|
end
|
|
|
|
it 'the request adds authorization headers' do
|
|
subject
|
|
end
|
|
end
|
|
|
|
context 'when localhost requests are allowed' do
|
|
let(:download_link) { 'http://192.168.2.120' }
|
|
let(:local_request_setting) { true }
|
|
|
|
before do
|
|
WebMock.stub_request(:get, download_link).to_return(body: lfs_content)
|
|
end
|
|
|
|
it_behaves_like 'lfs object is created'
|
|
end
|
|
|
|
context 'when a bad URL is used' do
|
|
where(download_link: ['/etc/passwd', 'ftp://example.com', 'http://127.0.0.2', 'http://192.168.2.120'])
|
|
|
|
with_them do
|
|
it 'does not download the file' do
|
|
expect(subject).not_to receive(:download_lfs_file!)
|
|
|
|
expect { subject.execute }.not_to change { LfsObject.count }
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when the URL points to a redirected URL' do
|
|
context 'that is blocked' do
|
|
where(redirect_link: ['ftp://example.com', 'http://127.0.0.2', 'http://192.168.2.120'])
|
|
|
|
with_them do
|
|
before do
|
|
WebMock.stub_request(:get, download_link).to_return(status: 301, headers: { 'Location' => redirect_link })
|
|
end
|
|
|
|
it_behaves_like 'no lfs object is created'
|
|
end
|
|
end
|
|
|
|
context 'that is not blocked' do
|
|
let(:redirect_link) { "http://example.com/"}
|
|
|
|
before do
|
|
WebMock.stub_request(:get, download_link).to_return(status: 301, headers: { 'Location' => redirect_link })
|
|
WebMock.stub_request(:get, redirect_link).to_return(body: lfs_content)
|
|
end
|
|
|
|
it_behaves_like 'lfs object is created'
|
|
end
|
|
end
|
|
|
|
context 'when the lfs object attributes are invalid' do
|
|
let(:oid) { 'foobar' }
|
|
|
|
before do
|
|
expect(lfs_object).to be_invalid
|
|
end
|
|
|
|
it_behaves_like 'no lfs object is created'
|
|
|
|
it 'does not download the file' do
|
|
expect(subject).not_to receive(:download_lfs_file!)
|
|
|
|
subject.execute
|
|
end
|
|
end
|
|
|
|
context 'when an lfs object with the same oid already exists' do
|
|
before do
|
|
create(:lfs_object, oid: oid)
|
|
end
|
|
|
|
it 'does not download the file' do
|
|
expect(subject).not_to receive(:download_lfs_file!)
|
|
|
|
subject.execute
|
|
end
|
|
end
|
|
end
|
|
end
|