2020-01-01 13:55:28 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-08-17 22:00:37 +05:30
|
|
|
require "spec_helper"
|
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
RSpec.describe Gitlab::Git::Tree do
|
2022-08-13 15:12:31 +05:30
|
|
|
let_it_be(:user) { create(:user) }
|
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
let(:project) { create(:project, :repository) }
|
|
|
|
let(:repository) { project.repository.raw }
|
2017-09-10 17:25:29 +05:30
|
|
|
|
2019-05-03 19:53:19 +05:30
|
|
|
shared_examples :repo do
|
2022-09-01 20:07:04 +05:30
|
|
|
subject(:tree) { Gitlab::Git::Tree.where(repository, sha, path, recursive, skip_flat_paths, pagination_params) }
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
let(:sha) { SeedRepo::Commit::ID }
|
|
|
|
let(:path) { nil }
|
|
|
|
let(:recursive) { false }
|
|
|
|
let(:pagination_params) { nil }
|
2022-09-01 20:07:04 +05:30
|
|
|
let(:skip_flat_paths) { false }
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
let(:entries) { tree.first }
|
|
|
|
let(:cursor) { tree.second }
|
|
|
|
|
|
|
|
it { expect(entries).to be_kind_of Array }
|
|
|
|
it { expect(entries.empty?).to be_falsey }
|
|
|
|
it { expect(entries.count(&:dir?)).to eq(2) }
|
|
|
|
it { expect(entries.count(&:file?)).to eq(10) }
|
|
|
|
it { expect(entries.count(&:submodule?)).to eq(2) }
|
|
|
|
it { expect(cursor&.next_cursor).to be_blank }
|
|
|
|
|
|
|
|
context 'with an invalid ref' do
|
|
|
|
let(:sha) { 'foobar-does-not-exist' }
|
|
|
|
|
|
|
|
it { expect(entries).to eq([]) }
|
|
|
|
it { expect(cursor).to be_nil }
|
2019-05-03 19:53:19 +05:30
|
|
|
end
|
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
context 'when path is provided' do
|
|
|
|
let(:path) { 'files' }
|
|
|
|
let(:recursive) { true }
|
2019-05-03 19:53:19 +05:30
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
it 'returns a list of tree objects' do
|
|
|
|
expect(entries.map(&:path)).to include('files/html',
|
|
|
|
'files/markdown/ruby-style-guide.md')
|
|
|
|
expect(entries.count).to be >= 10
|
|
|
|
expect(entries).to all(be_a(Gitlab::Git::Tree))
|
|
|
|
end
|
2019-05-03 19:53:19 +05:30
|
|
|
end
|
|
|
|
|
2017-08-17 22:00:37 +05:30
|
|
|
describe '#dir?' do
|
2022-01-26 12:08:38 +05:30
|
|
|
let(:dir) { entries.find(&:dir?) }
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
it { expect(dir).to be_kind_of Gitlab::Git::Tree }
|
|
|
|
it { expect(dir.id).to eq('3c122d2b7830eca25235131070602575cf8b41a1') }
|
|
|
|
it { expect(dir.commit_id).to eq(SeedRepo::Commit::ID) }
|
|
|
|
it { expect(dir.name).to eq('encoding') }
|
|
|
|
it { expect(dir.path).to eq('encoding') }
|
|
|
|
it { expect(dir.mode).to eq('40000') }
|
2019-05-03 19:53:19 +05:30
|
|
|
it { expect(dir.flat_path).to eq('encoding') }
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
context :subdir do
|
2020-04-22 19:07:51 +05:30
|
|
|
# rubocop: disable Rails/FindBy
|
|
|
|
# This is not ActiveRecord where..first
|
2021-10-27 15:23:28 +05:30
|
|
|
let(:path) { 'files' }
|
|
|
|
let(:subdir) { entries.first }
|
2020-04-22 19:07:51 +05:30
|
|
|
# rubocop: enable Rails/FindBy
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
it { expect(subdir).to be_kind_of Gitlab::Git::Tree }
|
|
|
|
it { expect(subdir.id).to eq('a1e8f8d745cc87e3a9248358d9352bb7f9a0aeba') }
|
|
|
|
it { expect(subdir.commit_id).to eq(SeedRepo::Commit::ID) }
|
|
|
|
it { expect(subdir.name).to eq('html') }
|
|
|
|
it { expect(subdir.path).to eq('files/html') }
|
2018-03-17 18:26:18 +05:30
|
|
|
it { expect(subdir.flat_path).to eq('files/html') }
|
2017-08-17 22:00:37 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context :subdir_file do
|
2020-04-22 19:07:51 +05:30
|
|
|
# rubocop: disable Rails/FindBy
|
|
|
|
# This is not ActiveRecord where..first
|
2021-10-27 15:23:28 +05:30
|
|
|
let(:path) { 'files/ruby' }
|
|
|
|
let(:subdir_file) { entries.first }
|
2020-04-22 19:07:51 +05:30
|
|
|
# rubocop: enable Rails/FindBy
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
it { expect(subdir_file).to be_kind_of Gitlab::Git::Tree }
|
|
|
|
it { expect(subdir_file.id).to eq('7e3e39ebb9b2bf433b4ad17313770fbe4051649c') }
|
|
|
|
it { expect(subdir_file.commit_id).to eq(SeedRepo::Commit::ID) }
|
|
|
|
it { expect(subdir_file.name).to eq('popen.rb') }
|
|
|
|
it { expect(subdir_file.path).to eq('files/ruby/popen.rb') }
|
2018-03-17 18:26:18 +05:30
|
|
|
it { expect(subdir_file.flat_path).to eq('files/ruby/popen.rb') }
|
2017-08-17 22:00:37 +05:30
|
|
|
end
|
2019-05-03 19:53:19 +05:30
|
|
|
|
|
|
|
context :flat_path do
|
|
|
|
let(:filename) { 'files/flat/path/correct/content.txt' }
|
2021-10-27 15:23:28 +05:30
|
|
|
let(:path) { 'files/flat' }
|
2020-04-22 19:07:51 +05:30
|
|
|
# rubocop: disable Rails/FindBy
|
|
|
|
# This is not ActiveRecord where..first
|
2021-10-27 15:23:28 +05:30
|
|
|
let(:subdir_file) { entries.first }
|
2020-04-22 19:07:51 +05:30
|
|
|
# rubocop: enable Rails/FindBy
|
2022-08-13 15:12:31 +05:30
|
|
|
let!(:sha) do
|
2022-10-11 01:57:18 +05:30
|
|
|
repository.commit_files(
|
2022-08-13 15:12:31 +05:30
|
|
|
user,
|
|
|
|
branch_name: 'HEAD',
|
|
|
|
message: "Create #{filename}",
|
|
|
|
actions: [{
|
|
|
|
action: :create,
|
|
|
|
file_path: filename,
|
|
|
|
contents: 'test'
|
|
|
|
}]
|
|
|
|
).newrev
|
|
|
|
end
|
|
|
|
|
2019-05-03 19:53:19 +05:30
|
|
|
it { expect(subdir_file.flat_path).to eq('files/flat/path/correct') }
|
2022-09-01 20:07:04 +05:30
|
|
|
|
|
|
|
context 'when skip_flat_paths is true' do
|
|
|
|
let(:skip_flat_paths) { true }
|
|
|
|
|
|
|
|
it { expect(subdir_file.flat_path).to be_blank }
|
|
|
|
end
|
2019-05-03 19:53:19 +05:30
|
|
|
end
|
2017-08-17 22:00:37 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
describe '#file?' do
|
2022-01-26 12:08:38 +05:30
|
|
|
let(:file) { entries.find(&:file?) }
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
it { expect(file).to be_kind_of Gitlab::Git::Tree }
|
|
|
|
it { expect(file.id).to eq('dfaa3f97ca337e20154a98ac9d0be76ddd1fcc82') }
|
|
|
|
it { expect(file.commit_id).to eq(SeedRepo::Commit::ID) }
|
|
|
|
it { expect(file.name).to eq('.gitignore') }
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#readme?' do
|
2022-01-26 12:08:38 +05:30
|
|
|
let(:file) { entries.find(&:readme?) }
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
it { expect(file).to be_kind_of Gitlab::Git::Tree }
|
|
|
|
it { expect(file.name).to eq('README.md') }
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#contributing?' do
|
2022-01-26 12:08:38 +05:30
|
|
|
let(:file) { entries.find(&:contributing?) }
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
it { expect(file).to be_kind_of Gitlab::Git::Tree }
|
|
|
|
it { expect(file.name).to eq('CONTRIBUTING.md') }
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#submodule?' do
|
2022-01-26 12:08:38 +05:30
|
|
|
let(:submodule) { entries.find(&:submodule?) }
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
it { expect(submodule).to be_kind_of Gitlab::Git::Tree }
|
|
|
|
it { expect(submodule.id).to eq('79bceae69cb5750d6567b223597999bfa91cb3b9') }
|
|
|
|
it { expect(submodule.commit_id).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') }
|
|
|
|
it { expect(submodule.name).to eq('gitlab-shell') }
|
|
|
|
end
|
|
|
|
end
|
2017-09-10 17:25:29 +05:30
|
|
|
|
2019-05-03 19:53:19 +05:30
|
|
|
describe '.where with Gitaly enabled' do
|
2021-10-27 15:23:28 +05:30
|
|
|
it_behaves_like :repo do
|
|
|
|
context 'with pagination parameters' do
|
|
|
|
let(:pagination_params) { { limit: 3, page_token: nil } }
|
|
|
|
|
|
|
|
it 'returns paginated list of tree objects' do
|
|
|
|
expect(entries.count).to eq(3)
|
|
|
|
expect(cursor.next_cursor).to be_present
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2019-05-03 19:53:19 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
describe '.where with Rugged enabled', :enable_rugged do
|
|
|
|
it 'calls out to the Rugged implementation' do
|
2020-01-01 13:55:28 +05:30
|
|
|
allow_next_instance_of(Rugged) do |instance|
|
|
|
|
allow(instance).to receive(:lookup).with(SeedRepo::Commit::ID)
|
|
|
|
end
|
2019-05-03 19:53:19 +05:30
|
|
|
|
2022-09-01 20:07:04 +05:30
|
|
|
described_class.where(repository, SeedRepo::Commit::ID, 'files', false, false)
|
2017-09-10 17:25:29 +05:30
|
|
|
end
|
2019-05-03 19:53:19 +05:30
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
it_behaves_like :repo do
|
2021-11-11 11:23:49 +05:30
|
|
|
describe 'Pagination' do
|
|
|
|
context 'with restrictive limit' do
|
|
|
|
let(:pagination_params) { { limit: 3, page_token: nil } }
|
|
|
|
|
|
|
|
it 'returns limited paginated list of tree objects' do
|
|
|
|
expect(entries.count).to eq(3)
|
|
|
|
expect(cursor.next_cursor).to be_present
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when limit is equal to number of entries' do
|
|
|
|
let(:entries_count) { entries.count }
|
|
|
|
|
|
|
|
it 'returns all entries without a cursor' do
|
2022-09-01 20:07:04 +05:30
|
|
|
result, cursor = Gitlab::Git::Tree.where(repository, sha, path, recursive, skip_flat_paths, { limit: entries_count, page_token: nil })
|
2021-11-11 11:23:49 +05:30
|
|
|
|
|
|
|
expect(cursor).to be_nil
|
|
|
|
expect(result.entries.count).to eq(entries_count)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when limit is 0' do
|
|
|
|
let(:pagination_params) { { limit: 0, page_token: nil } }
|
|
|
|
|
|
|
|
it 'returns empty result' do
|
|
|
|
expect(entries).to eq([])
|
|
|
|
expect(cursor).to be_nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when limit is missing' do
|
|
|
|
let(:pagination_params) { { limit: nil, page_token: nil } }
|
|
|
|
|
|
|
|
it 'returns empty result' do
|
|
|
|
expect(entries).to eq([])
|
|
|
|
expect(cursor).to be_nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when limit is negative' do
|
|
|
|
let(:entries_count) { entries.count }
|
|
|
|
|
|
|
|
it 'returns all entries' do
|
2022-09-01 20:07:04 +05:30
|
|
|
result, cursor = Gitlab::Git::Tree.where(repository, sha, path, recursive, skip_flat_paths, { limit: -1, page_token: nil })
|
2021-11-11 11:23:49 +05:30
|
|
|
|
|
|
|
expect(result.count).to eq(entries_count)
|
|
|
|
expect(cursor).to be_nil
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when token is provided' do
|
|
|
|
let(:pagination_params) { { limit: 1000, page_token: nil } }
|
|
|
|
let(:token) { entries.second.id }
|
|
|
|
|
|
|
|
it 'returns all entries after token' do
|
2022-09-01 20:07:04 +05:30
|
|
|
result, cursor = Gitlab::Git::Tree.where(repository, sha, path, recursive, skip_flat_paths, { limit: -1, page_token: token })
|
2021-11-11 11:23:49 +05:30
|
|
|
|
|
|
|
expect(result.count).to eq(entries.count - 2)
|
|
|
|
expect(cursor).to be_nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when token does not exist' do
|
|
|
|
let(:pagination_params) { { limit: 5, page_token: 'aabbccdd' } }
|
|
|
|
|
|
|
|
it 'raises a command error' do
|
2023-01-13 00:05:48 +05:30
|
|
|
expect { entries }.to raise_error(Gitlab::Git::CommandError, /could not find starting OID: aabbccdd/)
|
2021-11-11 11:23:49 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when limit is bigger than number of entries' do
|
|
|
|
let(:pagination_params) { { limit: 1000, page_token: nil } }
|
|
|
|
|
|
|
|
it 'returns only available entries' do
|
|
|
|
expect(entries.count).to be < 20
|
|
|
|
expect(cursor).to be_nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns all tree entries in specific order during cursor pagination' do
|
|
|
|
collected_entries = []
|
|
|
|
token = nil
|
|
|
|
|
|
|
|
expected_entries = entries
|
|
|
|
|
|
|
|
loop do
|
2022-09-01 20:07:04 +05:30
|
|
|
result, cursor = Gitlab::Git::Tree.where(repository, sha, path, recursive, skip_flat_paths, { limit: 5, page_token: token })
|
2021-11-11 11:23:49 +05:30
|
|
|
|
|
|
|
collected_entries += result.entries
|
|
|
|
token = cursor&.next_cursor
|
|
|
|
|
|
|
|
break if token.blank?
|
|
|
|
end
|
|
|
|
|
|
|
|
expect(collected_entries.map(&:path)).to match_array(expected_entries.map(&:path))
|
|
|
|
|
|
|
|
expected_order = [
|
|
|
|
collected_entries.select(&:dir?).map(&:path),
|
|
|
|
collected_entries.select(&:file?).map(&:path),
|
|
|
|
collected_entries.select(&:submodule?).map(&:path)
|
|
|
|
].flatten
|
2021-10-27 15:23:28 +05:30
|
|
|
|
2021-11-11 11:23:49 +05:30
|
|
|
expect(collected_entries.map(&:path)).to eq(expected_order)
|
2021-10-27 15:23:28 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-09-10 17:25:29 +05:30
|
|
|
end
|
2017-08-17 22:00:37 +05:30
|
|
|
end
|