2019-11-21 09:06:16 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-01-04 18:43:06 +00:00
|
|
|
require "spec_helper"
|
|
|
|
|
2020-06-24 18:09:03 +00:00
|
|
|
RSpec.describe Gitlab::Git::Blob, :seed_helper do
|
2018-12-23 07:34:35 +00:00
|
|
|
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '', 'group/project') }
|
2018-10-02 03:21:46 +00:00
|
|
|
let(:rugged) do
|
|
|
|
Rugged::Repository.new(File.join(TestEnv.repos_path, TEST_REPO_PATH))
|
|
|
|
end
|
2017-01-04 18:43:06 +00:00
|
|
|
|
2017-03-24 23:04:03 +00:00
|
|
|
describe 'initialize' do
|
2017-01-04 18:43:06 +00:00
|
|
|
let(:blob) { Gitlab::Git::Blob.new(name: 'test') }
|
|
|
|
|
|
|
|
it 'handles nil data' do
|
2020-02-19 12:09:13 +00:00
|
|
|
expect(described_class).not_to receive(:gitlab_blob_size)
|
|
|
|
|
2017-01-04 18:43:06 +00:00
|
|
|
expect(blob.name).to eq('test')
|
|
|
|
expect(blob.size).to eq(nil)
|
|
|
|
expect(blob.loaded_size).to eq(nil)
|
|
|
|
end
|
2020-02-19 12:09:13 +00:00
|
|
|
|
|
|
|
it 'records blob size' do
|
|
|
|
expect(described_class).to receive(:gitlab_blob_size).and_call_original
|
|
|
|
|
2020-02-20 12:08:51 +00:00
|
|
|
Gitlab::Git::Blob.new(name: 'test', size: 4, data: 'abcd')
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when untruncated' do
|
|
|
|
it 'attempts to record gitlab_blob_truncated_false' do
|
|
|
|
expect(described_class).to receive(:gitlab_blob_truncated_false).and_call_original
|
|
|
|
|
|
|
|
Gitlab::Git::Blob.new(name: 'test', size: 4, data: 'abcd')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when truncated' do
|
|
|
|
it 'attempts to record gitlab_blob_truncated_true' do
|
|
|
|
expect(described_class).to receive(:gitlab_blob_truncated_true).and_call_original
|
|
|
|
|
|
|
|
Gitlab::Git::Blob.new(name: 'test', size: 40, data: 'abcd')
|
|
|
|
end
|
2020-02-19 12:09:13 +00:00
|
|
|
end
|
2017-01-04 18:43:06 +00:00
|
|
|
end
|
|
|
|
|
2019-03-02 05:15:38 +00:00
|
|
|
shared_examples '.find' do
|
2018-01-21 05:00:39 +00:00
|
|
|
context 'nil path' do
|
|
|
|
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, nil) }
|
|
|
|
|
|
|
|
it { expect(blob).to eq(nil) }
|
|
|
|
end
|
|
|
|
|
2018-05-30 10:48:25 +00:00
|
|
|
context 'utf-8 branch' do
|
|
|
|
let(:blob) { Gitlab::Git::Blob.find(repository, 'Ääh-test-utf-8', "files/ruby/popen.rb")}
|
|
|
|
|
|
|
|
it { expect(blob.id).to eq(SeedRepo::RubyBlob::ID) }
|
|
|
|
end
|
|
|
|
|
2018-01-21 05:00:39 +00:00
|
|
|
context 'blank path' do
|
|
|
|
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, '') }
|
|
|
|
|
|
|
|
it { expect(blob).to eq(nil) }
|
|
|
|
end
|
|
|
|
|
2017-01-04 18:43:06 +00:00
|
|
|
context 'file in subdir' do
|
|
|
|
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "files/ruby/popen.rb") }
|
|
|
|
|
|
|
|
it { expect(blob.id).to eq(SeedRepo::RubyBlob::ID) }
|
|
|
|
it { expect(blob.name).to eq(SeedRepo::RubyBlob::NAME) }
|
|
|
|
it { expect(blob.path).to eq("files/ruby/popen.rb") }
|
|
|
|
it { expect(blob.commit_id).to eq(SeedRepo::Commit::ID) }
|
|
|
|
it { expect(blob.data[0..10]).to eq(SeedRepo::RubyBlob::CONTENT[0..10]) }
|
|
|
|
it { expect(blob.size).to eq(669) }
|
|
|
|
it { expect(blob.mode).to eq("100644") }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'file in root' do
|
|
|
|
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, ".gitignore") }
|
|
|
|
|
|
|
|
it { expect(blob.id).to eq("dfaa3f97ca337e20154a98ac9d0be76ddd1fcc82") }
|
|
|
|
it { expect(blob.name).to eq(".gitignore") }
|
|
|
|
it { expect(blob.path).to eq(".gitignore") }
|
|
|
|
it { expect(blob.commit_id).to eq(SeedRepo::Commit::ID) }
|
|
|
|
it { expect(blob.data[0..10]).to eq("*.rbc\n*.sas") }
|
|
|
|
it { expect(blob.size).to eq(241) }
|
|
|
|
it { expect(blob.mode).to eq("100644") }
|
2018-12-13 17:49:05 +00:00
|
|
|
it { expect(blob).not_to be_binary_in_repo }
|
2017-01-04 18:43:06 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'file in root with leading slash' do
|
|
|
|
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "/.gitignore") }
|
|
|
|
|
|
|
|
it { expect(blob.id).to eq("dfaa3f97ca337e20154a98ac9d0be76ddd1fcc82") }
|
|
|
|
it { expect(blob.name).to eq(".gitignore") }
|
|
|
|
it { expect(blob.path).to eq(".gitignore") }
|
|
|
|
it { expect(blob.commit_id).to eq(SeedRepo::Commit::ID) }
|
|
|
|
it { expect(blob.data[0..10]).to eq("*.rbc\n*.sas") }
|
|
|
|
it { expect(blob.size).to eq(241) }
|
|
|
|
it { expect(blob.mode).to eq("100644") }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'non-exist file' do
|
|
|
|
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "missing.rb") }
|
|
|
|
|
|
|
|
it { expect(blob).to be_nil }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'six submodule' do
|
|
|
|
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, 'six') }
|
|
|
|
|
|
|
|
it { expect(blob.id).to eq('409f37c4f05865e4fb208c771485f211a22c4c2d') }
|
|
|
|
it { expect(blob.data).to eq('') }
|
|
|
|
|
|
|
|
it 'does not get messed up by load_all_data!' do
|
|
|
|
blob.load_all_data!(repository)
|
|
|
|
expect(blob.data).to eq('')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not mark the blob as binary' do
|
2018-12-13 17:49:05 +00:00
|
|
|
expect(blob).not_to be_binary_in_repo
|
2017-01-04 18:43:06 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'large file' do
|
|
|
|
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, 'files/images/6049019_460s.jpg') }
|
|
|
|
let(:blob_size) { 111803 }
|
2017-08-01 11:17:11 +00:00
|
|
|
let(:stub_limit) { 1000 }
|
|
|
|
|
|
|
|
before do
|
|
|
|
stub_const('Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE', stub_limit)
|
|
|
|
end
|
2017-01-04 18:43:06 +00:00
|
|
|
|
|
|
|
it { expect(blob.size).to eq(blob_size) }
|
2017-08-01 11:17:11 +00:00
|
|
|
it { expect(blob.data.length).to eq(stub_limit) }
|
2017-01-04 18:43:06 +00:00
|
|
|
|
|
|
|
it 'check that this test is sane' do
|
2017-08-01 11:17:11 +00:00
|
|
|
# It only makes sense to test limiting if the blob is larger than the limit.
|
|
|
|
expect(blob.size).to be > Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE
|
2017-01-04 18:43:06 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'can load all data' do
|
|
|
|
blob.load_all_data!(repository)
|
|
|
|
expect(blob.data.length).to eq(blob_size)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'marks the blob as binary' do
|
2017-06-21 13:48:12 +00:00
|
|
|
expect(Gitlab::Git::Blob).to receive(:new)
|
|
|
|
.with(hash_including(binary: true))
|
|
|
|
.and_call_original
|
2017-01-04 18:43:06 +00:00
|
|
|
|
2018-12-13 17:49:05 +00:00
|
|
|
expect(blob).to be_binary_in_repo
|
2017-01-04 18:43:06 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-03-02 05:15:38 +00:00
|
|
|
describe '.find with Gitaly enabled' do
|
|
|
|
it_behaves_like '.find'
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '.find with Rugged enabled', :enable_rugged do
|
|
|
|
it 'calls out to the Rugged implementation' do
|
2019-12-07 00:07:51 +00:00
|
|
|
allow_next_instance_of(Rugged) do |instance|
|
|
|
|
allow(instance).to receive(:rev_parse).with(SeedRepo::Commit::ID).and_call_original
|
|
|
|
end
|
2019-03-02 05:15:38 +00:00
|
|
|
|
|
|
|
described_class.find(repository, SeedRepo::Commit::ID, 'files/images/6049019_460s.jpg')
|
|
|
|
end
|
|
|
|
|
|
|
|
it_behaves_like '.find'
|
|
|
|
end
|
|
|
|
|
2018-11-20 12:29:56 +00:00
|
|
|
describe '.raw' do
|
2017-01-04 18:43:06 +00:00
|
|
|
let(:raw_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::RubyBlob::ID) }
|
2017-09-21 11:22:12 +00:00
|
|
|
let(:bad_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::BigCommit::ID) }
|
|
|
|
|
2017-01-04 18:43:06 +00:00
|
|
|
it { expect(raw_blob.id).to eq(SeedRepo::RubyBlob::ID) }
|
|
|
|
it { expect(raw_blob.data[0..10]).to eq("require \'fi") }
|
|
|
|
it { expect(raw_blob.size).to eq(669) }
|
|
|
|
it { expect(raw_blob.truncated?).to be_falsey }
|
2017-09-21 11:22:12 +00:00
|
|
|
it { expect(bad_blob).to be_nil }
|
2017-01-04 18:43:06 +00:00
|
|
|
|
|
|
|
context 'large file' do
|
|
|
|
it 'limits the size of a large file' do
|
|
|
|
blob_size = Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE + 1
|
|
|
|
buffer = Array.new(blob_size, 0)
|
2018-10-02 03:21:46 +00:00
|
|
|
rugged_blob = Rugged::Blob.from_buffer(rugged, buffer.join(''))
|
2017-01-04 18:43:06 +00:00
|
|
|
blob = Gitlab::Git::Blob.raw(repository, rugged_blob)
|
|
|
|
|
|
|
|
expect(blob.size).to eq(blob_size)
|
|
|
|
expect(blob.loaded_size).to eq(Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE)
|
|
|
|
expect(blob.data.length).to eq(Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE)
|
|
|
|
expect(blob.truncated?).to be_truthy
|
|
|
|
|
|
|
|
blob.load_all_data!(repository)
|
|
|
|
expect(blob.loaded_size).to eq(blob_size)
|
|
|
|
end
|
|
|
|
end
|
2017-08-25 01:30:12 +00:00
|
|
|
|
|
|
|
context 'when sha references a tree' do
|
|
|
|
it 'returns nil' do
|
2018-10-02 03:21:46 +00:00
|
|
|
tree = rugged.rev_parse('master^{tree}')
|
2017-08-25 01:30:12 +00:00
|
|
|
|
|
|
|
blob = Gitlab::Git::Blob.raw(repository, tree.oid)
|
|
|
|
|
|
|
|
expect(blob).to be_nil
|
|
|
|
end
|
|
|
|
end
|
2017-01-04 18:43:06 +00:00
|
|
|
end
|
|
|
|
|
2017-08-01 11:49:57 +00:00
|
|
|
describe '.batch' do
|
2018-07-11 10:59:15 +00:00
|
|
|
let(:blob_references) do
|
|
|
|
[
|
|
|
|
[SeedRepo::Commit::ID, "files/ruby/popen.rb"],
|
|
|
|
[SeedRepo::Commit::ID, 'six']
|
|
|
|
]
|
|
|
|
end
|
2017-08-01 11:49:57 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
subject { described_class.batch(repository, blob_references) }
|
2017-08-01 11:49:57 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
it { expect(subject.size).to eq(blob_references.size) }
|
2017-08-01 11:49:57 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
context 'first blob' do
|
|
|
|
let(:blob) { subject[0] }
|
2017-08-01 11:49:57 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
it { expect(blob.id).to eq(SeedRepo::RubyBlob::ID) }
|
|
|
|
it { expect(blob.name).to eq(SeedRepo::RubyBlob::NAME) }
|
|
|
|
it { expect(blob.path).to eq("files/ruby/popen.rb") }
|
|
|
|
it { expect(blob.commit_id).to eq(SeedRepo::Commit::ID) }
|
|
|
|
it { expect(blob.data[0..10]).to eq(SeedRepo::RubyBlob::CONTENT[0..10]) }
|
|
|
|
it { expect(blob.size).to eq(669) }
|
|
|
|
it { expect(blob.mode).to eq("100644") }
|
|
|
|
end
|
2017-08-01 11:49:57 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
context 'second blob' do
|
|
|
|
let(:blob) { subject[1] }
|
2017-08-01 11:49:57 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
it { expect(blob.id).to eq('409f37c4f05865e4fb208c771485f211a22c4c2d') }
|
|
|
|
it { expect(blob.data).to eq('') }
|
|
|
|
it 'does not mark the blob as binary' do
|
2018-12-13 17:49:05 +00:00
|
|
|
expect(blob).not_to be_binary_in_repo
|
2017-08-01 11:49:57 +00:00
|
|
|
end
|
2018-07-11 10:59:15 +00:00
|
|
|
end
|
2017-08-01 11:49:57 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
context 'limiting' do
|
|
|
|
subject { described_class.batch(repository, blob_references, blob_size_limit: blob_size_limit) }
|
2017-08-01 11:49:57 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
context 'positive' do
|
|
|
|
let(:blob_size_limit) { 10 }
|
2017-08-01 11:49:57 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
it { expect(subject.first.data.size).to eq(10) }
|
|
|
|
end
|
2017-08-01 11:49:57 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
context 'zero' do
|
|
|
|
let(:blob_size_limit) { 0 }
|
2017-08-01 11:49:57 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
it 'only loads the metadata' do
|
|
|
|
expect(subject.first.size).not_to be(0)
|
|
|
|
expect(subject.first.data).to eq('')
|
2017-12-21 14:05:35 +00:00
|
|
|
end
|
2018-07-11 10:59:15 +00:00
|
|
|
end
|
2017-08-01 11:49:57 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
context 'negative' do
|
|
|
|
let(:blob_size_limit) { -1 }
|
2017-08-01 11:49:57 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
it 'ignores MAX_DATA_DISPLAY_SIZE' do
|
|
|
|
stub_const('Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE', 100)
|
2017-08-01 11:49:57 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
expect(subject.first.data.size).to eq(669)
|
2017-08-01 11:49:57 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2020-02-07 21:08:39 +00:00
|
|
|
|
|
|
|
context 'when large number of blobs requested' do
|
|
|
|
let(:first_batch) do
|
|
|
|
[
|
|
|
|
[SeedRepo::Commit::ID, 'files/ruby/popen.rb'],
|
|
|
|
[SeedRepo::Commit::ID, 'six']
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:second_batch) do
|
|
|
|
[
|
|
|
|
[SeedRepo::Commit::ID, 'some'],
|
|
|
|
[SeedRepo::Commit::ID, 'other']
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:third_batch) do
|
|
|
|
[
|
|
|
|
[SeedRepo::Commit::ID, 'files']
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:blob_references) do
|
|
|
|
first_batch + second_batch + third_batch
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:client) { repository.gitaly_blob_client }
|
|
|
|
let(:limit) { 10.megabytes }
|
|
|
|
|
|
|
|
before do
|
|
|
|
stub_const('Gitlab::Git::Blob::BATCH_SIZE', 2)
|
|
|
|
end
|
|
|
|
|
2020-04-09 15:09:29 +00:00
|
|
|
it 'fetches the blobs in batches' do
|
|
|
|
expect(client).to receive(:get_blobs).with(first_batch, limit).ordered
|
|
|
|
expect(client).to receive(:get_blobs).with(second_batch, limit).ordered
|
|
|
|
expect(client).to receive(:get_blobs).with(third_batch, limit).ordered
|
2020-02-07 21:08:39 +00:00
|
|
|
|
2020-04-09 15:09:29 +00:00
|
|
|
subject
|
2020-02-07 21:08:39 +00:00
|
|
|
end
|
|
|
|
end
|
2017-08-01 11:49:57 +00:00
|
|
|
end
|
|
|
|
|
2018-05-09 18:20:28 +00:00
|
|
|
describe '.batch_metadata' do
|
|
|
|
let(:blob_references) do
|
|
|
|
[
|
|
|
|
[SeedRepo::Commit::ID, "files/ruby/popen.rb"],
|
|
|
|
[SeedRepo::Commit::ID, 'six']
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
|
|
|
subject { described_class.batch_metadata(repository, blob_references) }
|
|
|
|
|
|
|
|
it 'returns an empty data attribute' do
|
|
|
|
first_blob, last_blob = subject
|
|
|
|
|
|
|
|
expect(first_blob.data).to be_blank
|
|
|
|
expect(first_blob.path).to eq("files/ruby/popen.rb")
|
|
|
|
expect(last_blob.data).to be_blank
|
|
|
|
expect(last_blob.path).to eq("six")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-08-25 01:30:12 +00:00
|
|
|
describe '.batch_lfs_pointers' do
|
2018-10-02 03:21:46 +00:00
|
|
|
let(:tree_object) { rugged.rev_parse('master^{tree}') }
|
2017-08-25 01:30:12 +00:00
|
|
|
|
|
|
|
let(:non_lfs_blob) do
|
|
|
|
Gitlab::Git::Blob.find(
|
|
|
|
repository,
|
|
|
|
'master',
|
|
|
|
'README.md'
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:lfs_blob) do
|
|
|
|
Gitlab::Git::Blob.find(
|
|
|
|
repository,
|
|
|
|
'33bcff41c232a11727ac6d660bd4b0c2ba86d63d',
|
|
|
|
'files/lfs/image.jpg'
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
it 'returns a list of Gitlab::Git::Blob' do
|
|
|
|
blobs = described_class.batch_lfs_pointers(repository, [lfs_blob.id])
|
2018-01-25 09:46:15 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
expect(blobs.count).to eq(1)
|
|
|
|
expect(blobs).to all( be_a(Gitlab::Git::Blob) )
|
|
|
|
expect(blobs).to be_an(Array)
|
|
|
|
end
|
2018-01-25 09:46:15 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
it 'accepts blob IDs as a lazy enumerator' do
|
|
|
|
blobs = described_class.batch_lfs_pointers(repository, [lfs_blob.id].lazy)
|
2018-01-25 09:46:15 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
expect(blobs.count).to eq(1)
|
|
|
|
expect(blobs).to all( be_a(Gitlab::Git::Blob) )
|
|
|
|
end
|
2017-08-25 01:30:12 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
it 'handles empty list of IDs gracefully' do
|
|
|
|
blobs_1 = described_class.batch_lfs_pointers(repository, [].lazy)
|
|
|
|
blobs_2 = described_class.batch_lfs_pointers(repository, [])
|
2018-01-17 13:21:46 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
expect(blobs_1).to eq([])
|
|
|
|
expect(blobs_2).to eq([])
|
|
|
|
end
|
2017-08-25 01:30:12 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
it 'silently ignores tree objects' do
|
|
|
|
blobs = described_class.batch_lfs_pointers(repository, [tree_object.oid])
|
2018-01-17 13:21:46 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
expect(blobs).to eq([])
|
|
|
|
end
|
2018-01-17 13:21:46 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
it 'silently ignores non lfs objects' do
|
|
|
|
blobs = described_class.batch_lfs_pointers(repository, [non_lfs_blob.id])
|
2017-08-25 01:30:12 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
expect(blobs).to eq([])
|
2017-08-25 01:30:12 +00:00
|
|
|
end
|
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
it 'avoids loading large blobs into memory' do
|
|
|
|
# This line could call `lookup` on `repository`, so do here before mocking.
|
|
|
|
non_lfs_blob_id = non_lfs_blob.id
|
|
|
|
|
|
|
|
expect(repository).not_to receive(:lookup)
|
2017-08-25 01:30:12 +00:00
|
|
|
|
2018-07-11 10:59:15 +00:00
|
|
|
described_class.batch_lfs_pointers(repository, [non_lfs_blob_id])
|
2017-08-25 01:30:12 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-04-02 12:08:18 +00:00
|
|
|
describe 'encoding', :aggregate_failures do
|
2017-01-04 18:43:06 +00:00
|
|
|
context 'file with russian text' do
|
|
|
|
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "encoding/russian.rb") }
|
|
|
|
|
2020-04-02 12:08:18 +00:00
|
|
|
it 'has the correct blob attributes' do
|
|
|
|
expect(blob.name).to eq("russian.rb")
|
|
|
|
expect(blob.data.lines.first).to eq("Хороший файл")
|
|
|
|
expect(blob.size).to eq(23)
|
|
|
|
expect(blob.truncated?).to be_falsey
|
|
|
|
# Run it twice since data is encoded after the first run
|
|
|
|
expect(blob.truncated?).to be_falsey
|
|
|
|
expect(blob.mode).to eq("100755")
|
|
|
|
end
|
2017-01-04 18:43:06 +00:00
|
|
|
end
|
|
|
|
|
2019-04-25 07:39:27 +00:00
|
|
|
context 'file with Japanese text' do
|
2017-01-04 18:43:06 +00:00
|
|
|
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "encoding/テスト.txt") }
|
|
|
|
|
2020-04-02 12:08:18 +00:00
|
|
|
it 'has the correct blob attributes' do
|
|
|
|
expect(blob.name).to eq("テスト.txt")
|
|
|
|
expect(blob.data).to include("これはテスト")
|
|
|
|
expect(blob.size).to eq(340)
|
|
|
|
expect(blob.mode).to eq("100755")
|
|
|
|
expect(blob.truncated?).to be_falsey
|
|
|
|
end
|
2017-01-04 18:43:06 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'file with ISO-8859 text' do
|
|
|
|
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::LastCommit::ID, "encoding/iso8859.txt") }
|
|
|
|
|
2020-04-02 12:08:18 +00:00
|
|
|
it 'has the correct blob attributes' do
|
|
|
|
expect(blob.name).to eq("iso8859.txt")
|
|
|
|
expect(blob.loaded_size).to eq(4)
|
|
|
|
expect(blob.size).to eq(4)
|
|
|
|
expect(blob.mode).to eq("100644")
|
|
|
|
expect(blob.truncated?).to be_falsey
|
|
|
|
end
|
2017-01-04 18:43:06 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'mode' do
|
|
|
|
context 'file regular' do
|
|
|
|
let(:blob) do
|
|
|
|
Gitlab::Git::Blob.find(
|
|
|
|
repository,
|
|
|
|
'fa1b1e6c004a68b7d8763b86455da9e6b23e36d6',
|
|
|
|
'files/ruby/regex.rb'
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it { expect(blob.name).to eq('regex.rb') }
|
|
|
|
it { expect(blob.path).to eq('files/ruby/regex.rb') }
|
|
|
|
it { expect(blob.size).to eq(1200) }
|
|
|
|
it { expect(blob.mode).to eq("100644") }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'file binary' do
|
|
|
|
let(:blob) do
|
|
|
|
Gitlab::Git::Blob.find(
|
|
|
|
repository,
|
|
|
|
'fa1b1e6c004a68b7d8763b86455da9e6b23e36d6',
|
|
|
|
'files/executables/ls'
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it { expect(blob.name).to eq('ls') }
|
|
|
|
it { expect(blob.path).to eq('files/executables/ls') }
|
|
|
|
it { expect(blob.size).to eq(110080) }
|
|
|
|
it { expect(blob.mode).to eq("100755") }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'file symlink to regular' do
|
|
|
|
let(:blob) do
|
|
|
|
Gitlab::Git::Blob.find(
|
|
|
|
repository,
|
|
|
|
'fa1b1e6c004a68b7d8763b86455da9e6b23e36d6',
|
|
|
|
'files/links/ruby-style-guide.md'
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it { expect(blob.name).to eq('ruby-style-guide.md') }
|
|
|
|
it { expect(blob.path).to eq('files/links/ruby-style-guide.md') }
|
|
|
|
it { expect(blob.size).to eq(31) }
|
|
|
|
it { expect(blob.mode).to eq("120000") }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'file symlink to binary' do
|
|
|
|
let(:blob) do
|
|
|
|
Gitlab::Git::Blob.find(
|
|
|
|
repository,
|
|
|
|
'fa1b1e6c004a68b7d8763b86455da9e6b23e36d6',
|
|
|
|
'files/links/touch'
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it { expect(blob.name).to eq('touch') }
|
|
|
|
it { expect(blob.path).to eq('files/links/touch') }
|
|
|
|
it { expect(blob.size).to eq(20) }
|
|
|
|
it { expect(blob.mode).to eq("120000") }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-03-24 23:04:03 +00:00
|
|
|
describe 'lfs_pointers' do
|
2017-01-04 18:43:06 +00:00
|
|
|
context 'file a valid lfs pointer' do
|
|
|
|
let(:blob) do
|
|
|
|
Gitlab::Git::Blob.find(
|
|
|
|
repository,
|
|
|
|
'33bcff41c232a11727ac6d660bd4b0c2ba86d63d',
|
|
|
|
'files/lfs/image.jpg'
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it { expect(blob.lfs_pointer?).to eq(true) }
|
|
|
|
it { expect(blob.lfs_oid).to eq("4206f951d2691c78aac4c0ce9f2b23580b2c92cdcc4336e1028742c0274938e0") }
|
2017-04-17 23:28:18 +00:00
|
|
|
it { expect(blob.lfs_size).to eq(19548) }
|
2017-01-04 18:43:06 +00:00
|
|
|
it { expect(blob.id).to eq("f4d76af13003d1106be7ac8c5a2a3d37ddf32c2a") }
|
|
|
|
it { expect(blob.name).to eq("image.jpg") }
|
|
|
|
it { expect(blob.path).to eq("files/lfs/image.jpg") }
|
|
|
|
it { expect(blob.size).to eq(130) }
|
|
|
|
it { expect(blob.mode).to eq("100644") }
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'file an invalid lfs pointer' do
|
|
|
|
context 'with correct version header but incorrect size and oid' do
|
|
|
|
let(:blob) do
|
|
|
|
Gitlab::Git::Blob.find(
|
|
|
|
repository,
|
|
|
|
'33bcff41c232a11727ac6d660bd4b0c2ba86d63d',
|
|
|
|
'files/lfs/archive-invalid.tar'
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it { expect(blob.lfs_pointer?).to eq(false) }
|
|
|
|
it { expect(blob.lfs_oid).to eq(nil) }
|
|
|
|
it { expect(blob.lfs_size).to eq(nil) }
|
|
|
|
it { expect(blob.id).to eq("f8a898db217a5a85ed8b3d25b34c1df1d1094c46") }
|
|
|
|
it { expect(blob.name).to eq("archive-invalid.tar") }
|
|
|
|
it { expect(blob.path).to eq("files/lfs/archive-invalid.tar") }
|
|
|
|
it { expect(blob.size).to eq(43) }
|
|
|
|
it { expect(blob.mode).to eq("100644") }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with correct version header and size but incorrect size and oid' do
|
|
|
|
let(:blob) do
|
|
|
|
Gitlab::Git::Blob.find(
|
|
|
|
repository,
|
|
|
|
'33bcff41c232a11727ac6d660bd4b0c2ba86d63d',
|
|
|
|
'files/lfs/picture-invalid.png'
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it { expect(blob.lfs_pointer?).to eq(false) }
|
|
|
|
it { expect(blob.lfs_oid).to eq(nil) }
|
2017-04-17 23:28:18 +00:00
|
|
|
it { expect(blob.lfs_size).to eq(1575078) }
|
2017-01-04 18:43:06 +00:00
|
|
|
it { expect(blob.id).to eq("5ae35296e1f95c1ef9feda1241477ed29a448572") }
|
|
|
|
it { expect(blob.name).to eq("picture-invalid.png") }
|
|
|
|
it { expect(blob.path).to eq("files/lfs/picture-invalid.png") }
|
|
|
|
it { expect(blob.size).to eq(57) }
|
|
|
|
it { expect(blob.mode).to eq("100644") }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with correct version header and size but invalid size and oid' do
|
|
|
|
let(:blob) do
|
|
|
|
Gitlab::Git::Blob.find(
|
|
|
|
repository,
|
|
|
|
'33bcff41c232a11727ac6d660bd4b0c2ba86d63d',
|
|
|
|
'files/lfs/file-invalid.zip'
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it { expect(blob.lfs_pointer?).to eq(false) }
|
|
|
|
it { expect(blob.lfs_oid).to eq(nil) }
|
|
|
|
it { expect(blob.lfs_size).to eq(nil) }
|
|
|
|
it { expect(blob.id).to eq("d831981bd876732b85a1bcc6cc01210c9f36248f") }
|
|
|
|
it { expect(blob.name).to eq("file-invalid.zip") }
|
|
|
|
it { expect(blob.path).to eq("files/lfs/file-invalid.zip") }
|
|
|
|
it { expect(blob.size).to eq(60) }
|
|
|
|
it { expect(blob.mode).to eq("100644") }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2018-02-28 22:22:44 +00:00
|
|
|
|
|
|
|
describe '#load_all_data!' do
|
|
|
|
let(:full_data) { 'abcd' }
|
|
|
|
let(:blob) { Gitlab::Git::Blob.new(name: 'test', size: 4, data: 'abc') }
|
|
|
|
|
|
|
|
subject { blob.load_all_data!(repository) }
|
|
|
|
|
|
|
|
it 'loads missing data' do
|
2018-07-09 10:02:02 +00:00
|
|
|
expect(repository.gitaly_blob_client).to receive(:get_blob)
|
|
|
|
.and_return(double(:response, data: full_data))
|
2018-02-28 22:22:44 +00:00
|
|
|
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(blob.data).to eq(full_data)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with a fully loaded blob' do
|
|
|
|
let(:blob) { Gitlab::Git::Blob.new(name: 'test', size: 4, data: full_data) }
|
|
|
|
|
|
|
|
it "doesn't perform any loading" do
|
2018-07-09 10:02:02 +00:00
|
|
|
expect(repository.gitaly_blob_client).not_to receive(:get_blob)
|
2018-02-28 22:22:44 +00:00
|
|
|
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(blob.data).to eq(full_data)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2020-02-18 09:09:24 +00:00
|
|
|
|
2020-02-25 18:09:02 +00:00
|
|
|
describe '#truncated?' do
|
|
|
|
context 'when blob.size is nil' do
|
|
|
|
let(:nil_size_blob) { Gitlab::Git::Blob.new(name: 'test', data: 'abcd') }
|
|
|
|
|
|
|
|
it 'returns false' do
|
|
|
|
expect(nil_size_blob.truncated?).to be_falsey
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when blob.data is missing' do
|
|
|
|
let(:nil_data_blob) { Gitlab::Git::Blob.new(name: 'test', size: 4) }
|
|
|
|
|
|
|
|
it 'returns false' do
|
|
|
|
expect(nil_data_blob.truncated?).to be_falsey
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the blob is truncated' do
|
|
|
|
let(:truncated_blob) { Gitlab::Git::Blob.new(name: 'test', size: 40, data: 'abcd') }
|
|
|
|
|
|
|
|
it 'returns true' do
|
|
|
|
expect(truncated_blob.truncated?).to be_truthy
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the blob is untruncated' do
|
|
|
|
let(:untruncated_blob) { Gitlab::Git::Blob.new(name: 'test', size: 4, data: 'abcd') }
|
|
|
|
|
|
|
|
it 'returns false' do
|
|
|
|
expect(untruncated_blob.truncated?).to be_falsey
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-02-18 09:09:24 +00:00
|
|
|
describe 'metrics' do
|
|
|
|
it 'defines :gitlab_blob_truncated_true counter' do
|
|
|
|
expect(described_class).to respond_to(:gitlab_blob_truncated_true)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'defines :gitlab_blob_truncated_false counter' do
|
|
|
|
expect(described_class).to respond_to(:gitlab_blob_truncated_false)
|
|
|
|
end
|
2020-02-18 21:09:11 +00:00
|
|
|
|
|
|
|
it 'defines :gitlab_blob_size histogram' do
|
|
|
|
expect(described_class).to respond_to(:gitlab_blob_size)
|
|
|
|
end
|
2020-02-18 09:09:24 +00:00
|
|
|
end
|
2020-04-23 09:09:46 +00:00
|
|
|
|
|
|
|
describe '#lines' do
|
|
|
|
context 'when the encoding cannot be detected' do
|
|
|
|
it 'successfully splits the data' do
|
|
|
|
data = "test\nblob"
|
|
|
|
blob = Gitlab::Git::Blob.new(name: 'test', size: data.bytesize, data: data)
|
|
|
|
expect(blob).to receive(:ruby_encoding) { nil }
|
|
|
|
|
|
|
|
expect(blob.lines).to eq(data.split("\n"))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-01-04 18:43:06 +00:00
|
|
|
end
|