gitlab-org--gitlab-foss/spec/services/files/multi_service_spec.rb

269 lines
7.1 KiB
Ruby

# frozen_string_literal: true
require "spec_helper"
RSpec.describe Files::MultiService do
subject { described_class.new(project, user, commit_params) }
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user) }
let(:branch_name) { project.default_branch }
let(:original_file_path) { 'files/ruby/popen.rb' }
let(:new_file_path) { 'files/ruby/popen.rb' }
let(:file_content) { 'New content' }
let(:action) { 'update' }
let(:commit_message) { 'Update File' }
let!(:original_commit_id) do
Gitlab::Git::Commit.last_for_path(project.repository, branch_name, original_file_path).sha
end
let(:default_action) do
{
action: action,
file_path: new_file_path,
previous_path: original_file_path,
content: file_content,
last_commit_id: original_commit_id
}
end
let(:actions) { [default_action] }
let(:commit_params) do
{
commit_message: commit_message,
branch_name: branch_name,
start_branch: branch_name,
actions: actions
}
end
before do
project.add_maintainer(user)
end
describe '#execute' do
context 'with a valid action' do
it 'returns a hash with the :success status' do
results = subject.execute
expect(results[:status]).to eq(:success)
end
end
context 'with an invalid action' do
let(:action) { 'rename' }
it 'returns a hash with the :error status' do
results = subject.execute
expect(results[:status]).to eq(:error)
expect(results[:message]).to match(/Unknown action/)
end
end
describe 'Updating files' do
context 'when the file has been previously updated' do
before do
update_file(original_file_path)
end
it 'rejects the commit' do
results = subject.execute
expect(results[:status]).to eq(:error)
expect(results[:message]).to match(new_file_path)
end
end
context 'when the file have not been modified' do
it 'accepts the commit' do
results = subject.execute
expect(results[:status]).to eq(:success)
end
end
end
describe 'changing execute_filemode of a file' do
let(:commit_message) { 'Chmod +x file' }
let(:file_path) { original_file_path }
let(:default_action) do
{
action: 'chmod',
file_path: file_path,
execute_filemode: true
}
end
it 'accepts the commit' do
results = subject.execute
expect(results[:status]).to eq(:success)
end
it 'updates the execute_filemode of the file' do
expect { subject.execute }.to change { repository.blob_at_branch(branch_name, file_path).mode }.from('100644').to('100755')
end
context "when the file doesn't exists" do
let(:file_path) { 'files/wrong_path.rb' }
it 'rejects the commit' do
results = subject.execute
expect(results[:status]).to eq(:error)
expect(results[:message]).to eq("A file with this name doesn't exist")
end
end
end
context 'when moving a file' do
let(:action) { 'move' }
let(:new_file_path) { 'files/ruby/new_popen.rb' }
let(:result) { subject.execute }
let(:blob) { repository.blob_at_branch(branch_name, new_file_path) }
context 'when original file has been updated' do
before do
update_file(original_file_path)
end
it 'rejects the commit' do
expect(result[:status]).to eq(:error)
expect(result[:message]).to match(original_file_path)
end
end
context 'when original file has not been updated' do
it 'moves the file' do
expect(result[:status]).to eq(:success)
expect(blob).to be_present
expect(blob.data).to eq(file_content)
end
context 'when content is nil' do
let(:file_content) { nil }
it 'moves the existing content untouched' do
original_content = repository.blob_at_branch(branch_name, original_file_path).data
expect(result[:status]).to eq(:success)
expect(blob).to be_present
expect(blob.data).to eq(original_content)
end
end
context 'when content is an empty string' do
let(:file_content) { '' }
it 'moves the file and empties it' do
expect(result[:status]).to eq(:success)
expect(blob).not_to be_nil
expect(blob.data).to eq('')
end
end
end
end
context 'when creating a file matching an LFS filter' do
let(:action) { 'create' }
let(:branch_name) { 'lfs' }
let(:new_file_path) { 'test_file.lfs' }
before do
allow(project).to receive(:lfs_enabled?).and_return(true)
end
it 'creates an LFS pointer' do
subject.execute
blob = repository.blob_at('lfs', new_file_path)
expect(blob.data).to start_with(Gitlab::Git::LfsPointerFile::VERSION_LINE)
end
it "creates an LfsObject with the file's content" do
subject.execute
expect(LfsObject.last.file.read).to eq file_content
end
context 'with base64 encoded content' do
let(:raw_file_content) { 'Raw content' }
let(:file_content) { Base64.encode64(raw_file_content) }
let(:actions) { [default_action.merge(encoding: 'base64')] }
it 'creates an LFS pointer' do
subject.execute
blob = repository.blob_at('lfs', new_file_path)
expect(blob.data).to start_with(Gitlab::Git::LfsPointerFile::VERSION_LINE)
end
it "creates an LfsObject with the file's content" do
subject.execute
expect(LfsObject.last.file.read).to eq raw_file_content
end
end
it 'links the LfsObject to the project' do
expect do
subject.execute
end.to change { project.lfs_objects.count }.by(1)
end
end
context 'when file status validation is skipped' do
let(:action) { 'create' }
let(:new_file_path) { 'files/ruby/new_file.rb' }
it 'does not check the last commit' do
expect(Gitlab::Git::Commit).not_to receive(:last_for_path)
subject.execute
end
it 'creates the file' do
subject.execute
blob = project.repository.blob_at_branch(branch_name, new_file_path)
expect(blob).to be_present
end
end
context 'when force is set to true and branch already exists' do
let(:commit_params) do
{
commit_message: commit_message,
branch_name: 'feature',
start_branch: 'master',
actions: actions,
force: true
}
end
it 'is still a success' do
expect(subject.execute[:status]).to eq(:success)
end
end
end
def update_file(path)
params = {
file_path: path,
start_branch: branch_name,
branch_name: branch_name,
commit_message: 'Update file',
file_content: 'New content'
}
Files::UpdateService.new(project, user, params).execute
end
end