debian-mirror-gitlab/spec/services/projects/forks/sync_service_spec.rb
2023-05-27 22:25:52 +05:30

185 lines
6.7 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Projects::Forks::SyncService, feature_category: :source_code_management do
include ProjectForksHelper
include RepoHelpers
let_it_be(:user) { create(:user) }
let_it_be(:source_project) { create(:project, :repository, :public) }
let_it_be(:project) { fork_project(source_project, user, { repository: true }) }
let(:fork_branch) { project.default_branch }
let(:service) { described_class.new(project, user, fork_branch) }
def details
Projects::Forks::Details.new(project, fork_branch)
end
def expect_to_cancel_exclusive_lease
expect(Gitlab::ExclusiveLease).to receive(:cancel)
end
describe '#execute' do
context 'when fork is up-to-date with the upstream' do
it 'does not perform merge' do
expect_to_cancel_exclusive_lease
expect(project.repository).not_to receive(:merge_to_branch)
expect(project.repository).not_to receive(:ff_merge)
expect(service.execute).to be_success
end
end
context 'when fork is behind the upstream' do
let_it_be(:base_commit) { source_project.commit.sha }
before_all do
source_project.repository.commit_files(
user,
branch_name: source_project.repository.root_ref, message: 'Commit to root ref',
actions: [{ action: :create, file_path: 'encoding/CHANGELOG', content: 'One more' }]
)
source_project.repository.commit_files(
user,
branch_name: source_project.repository.root_ref, message: 'Another commit to root ref',
actions: [{ action: :create, file_path: 'encoding/NEW-CHANGELOG', content: 'One more time' }]
)
end
before do
project.repository.create_branch(fork_branch, base_commit)
end
context 'when fork is not ahead of the upstream' do
let(:fork_branch) { 'fork-without-new-commits' }
it 'updates the fork using ff merge' do
expect_to_cancel_exclusive_lease
expect(project.commit(fork_branch).sha).to eq(base_commit)
expect(project.repository).to receive(:ff_merge)
.with(user, source_project.commit.sha, fork_branch, target_sha: base_commit)
.and_call_original
expect do
expect(service.execute).to be_success
end.to change { details.counts }.from({ ahead: 0, behind: 2 }).to({ ahead: 0, behind: 0 })
end
end
context 'when fork is ahead of the upstream' do
context 'and has conflicts with the upstream', :use_clean_rails_redis_caching do
let(:fork_branch) { 'fork-with-conflicts' }
it 'returns an error' do
project.repository.commit_files(
user,
branch_name: fork_branch, message: 'Committing something',
actions: [{ action: :create, file_path: 'encoding/CHANGELOG', content: 'New file' }]
)
expect_to_cancel_exclusive_lease
expect(details).not_to have_conflicts
expect do
result = service.execute
expect(result).to be_error
expect(result.message).to eq("9:merging commits: merge: there are conflicting files.")
end.not_to change { details.counts }
expect(details).to have_conflicts
end
end
context 'and does not have conflicts with the upstream' do
let(:fork_branch) { 'fork-with-new-commits' }
it 'updates the fork using merge' do
project.repository.commit_files(
user,
branch_name: fork_branch, message: 'Committing completely new changelog',
actions: [{ action: :create, file_path: 'encoding/COMPLETELY-NEW-CHANGELOG', content: 'New file' }]
)
commit_message = "Merge branch #{source_project.path}:#{source_project.default_branch} into #{fork_branch}"
expect(project.repository).to receive(:merge_to_branch).with(
user,
source_sha: source_project.commit.sha,
target_branch: fork_branch,
target_sha: project.commit(fork_branch).sha,
message: commit_message
).and_call_original
expect_to_cancel_exclusive_lease
expect do
expect(service.execute).to be_success
end.to change { details.counts }.from({ ahead: 1, behind: 2 }).to({ ahead: 2, behind: 0 })
commits = project.repository.commits_between(source_project.commit.sha, project.commit(fork_branch).sha)
expect(commits.map(&:message)).to eq([
"Committing completely new changelog",
commit_message
])
end
end
end
context 'when a merge cannot happen due to another ongoing merge' do
it 'does not merge' do
expect(service).to receive(:perform_merge).and_return(nil)
result = service.execute
expect(result).to be_error
expect(result.message).to eq(described_class::ONGOING_MERGE_ERROR)
end
end
context 'when upstream branch contains lfs reference' do
let(:source_project) { create(:project, :repository, :public) }
let(:project) { fork_project(source_project, user, { repository: true }) }
let(:fork_branch) { 'fork-fetches-lfs-pointers' }
before do
source_project.change_head('lfs')
allow(source_project).to receive(:lfs_enabled?).and_return(true)
allow(project).to receive(:lfs_enabled?).and_return(true)
create_file_in_repo(source_project, 'lfs', 'lfs', 'one.lfs', 'One')
create_file_in_repo(source_project, 'lfs', 'lfs', 'two.lfs', 'Two')
end
it 'links fetched lfs objects to the fork project', :aggregate_failures do
expect_to_cancel_exclusive_lease
expect do
expect(service.execute).to be_success
end.to change { project.reload.lfs_objects.size }.from(0).to(2)
.and change { details.counts }.from({ ahead: 0, behind: 3 }).to({ ahead: 0, behind: 0 })
expect(project.lfs_objects).to match_array(source_project.lfs_objects)
end
context 'and there are too many of them for a single sync' do
let(:fork_branch) { 'fork-too-many-lfs-pointers' }
it 'updates the fork successfully' do
expect_to_cancel_exclusive_lease
stub_const('Projects::LfsPointers::LfsLinkService::MAX_OIDS', 1)
expect do
result = service.execute
expect(result).to be_error
expect(result.message).to eq('Too many LFS object ids to link, please push them manually')
end.not_to change { details.counts }
end
end
end
end
end
end