summaryrefslogtreecommitdiff
path: root/spec/services/projects
diff options
context:
space:
mode:
authorYorick Peterse <yorickpeterse@gmail.com>2019-01-11 18:29:01 +0100
committerYorick Peterse <yorickpeterse@gmail.com>2019-01-16 14:25:14 +0100
commit52eeb56bf033e0695acba6c236ed6a9a40bc8a4d (patch)
tree0b144c95b893193457a5e40e899d1f311e48810d /spec/services/projects
parent3e9c9f97273efab6b623966597242811f8896024 (diff)
downloadgitlab-ce-52eeb56bf033e0695acba6c236ed6a9a40bc8a4d.tar.gz
Refactor code for protecting default branches
This refactors some of the logic used for protecting default branches, in particular Project#after_create_default_branch. The logic for this method is moved into a separate service class. Ideally we'd get rid of Project#after_create_default_branch entirely, but unfortunately Project#after_import depends on it. This means it has to stick around until we also refactor Project#after_import. For branch protection levels we introduce Gitlab::Access::BranchProtection, which provides a small wrapper around Integer based branch protection levels. Using this class removes the need for having to constantly refer to Gitlab::Access::PROTECTION_* constants.
Diffstat (limited to 'spec/services/projects')
-rw-r--r--spec/services/projects/protect_default_branch_service_spec.rb242
1 files changed, 242 insertions, 0 deletions
diff --git a/spec/services/projects/protect_default_branch_service_spec.rb b/spec/services/projects/protect_default_branch_service_spec.rb
new file mode 100644
index 00000000000..c145b2c06c6
--- /dev/null
+++ b/spec/services/projects/protect_default_branch_service_spec.rb
@@ -0,0 +1,242 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Projects::ProtectDefaultBranchService do
+ let(:service) { described_class.new(project) }
+ let(:project) { instance_spy(Project) }
+
+ describe '#execute' do
+ before do
+ allow(service)
+ .to receive(:protect_default_branch)
+ end
+
+ context 'without a default branch' do
+ it 'does nothing' do
+ allow(service)
+ .to receive(:default_branch)
+ .and_return(nil)
+
+ service.execute
+
+ expect(service)
+ .not_to have_received(:protect_default_branch)
+ end
+ end
+
+ context 'with a default branch' do
+ it 'protects the default branch' do
+ allow(service)
+ .to receive(:default_branch)
+ .and_return('master')
+
+ service.execute
+
+ expect(service)
+ .to have_received(:protect_default_branch)
+ end
+ end
+ end
+
+ describe '#protect_default_branch' do
+ before do
+ allow(service)
+ .to receive(:default_branch)
+ .and_return('master')
+
+ allow(project)
+ .to receive(:change_head)
+ .with('master')
+
+ allow(service)
+ .to receive(:create_protected_branch)
+ end
+
+ context 'when branch protection is needed' do
+ before do
+ allow(service)
+ .to receive(:protect_branch?)
+ .and_return(true)
+
+ allow(service)
+ .to receive(:create_protected_branch)
+ end
+
+ it 'changes the HEAD of the project' do
+ service.protect_default_branch
+
+ expect(project)
+ .to have_received(:change_head)
+ end
+
+ it 'protects the default branch' do
+ service.protect_default_branch
+
+ expect(service)
+ .to have_received(:create_protected_branch)
+ end
+ end
+
+ context 'when branch protection is not needed' do
+ before do
+ allow(service)
+ .to receive(:protect_branch?)
+ .and_return(false)
+ end
+
+ it 'changes the HEAD of the project' do
+ service.protect_default_branch
+
+ expect(project)
+ .to have_received(:change_head)
+ end
+
+ it 'does not protect the default branch' do
+ service.protect_default_branch
+
+ expect(service)
+ .not_to have_received(:create_protected_branch)
+ end
+ end
+ end
+
+ describe '#create_protected_branch' do
+ it 'creates the protected branch' do
+ creator = instance_spy(User)
+ create_service = instance_spy(ProtectedBranches::CreateService)
+ access_level = Gitlab::Access::DEVELOPER
+ params = {
+ name: 'master',
+ push_access_levels_attributes: [{ access_level: access_level }],
+ merge_access_levels_attributes: [{ access_level: access_level }]
+ }
+
+ allow(project)
+ .to receive(:creator)
+ .and_return(creator)
+
+ allow(ProtectedBranches::CreateService)
+ .to receive(:new)
+ .with(project, creator, params)
+ .and_return(create_service)
+
+ allow(service)
+ .to receive(:push_access_level)
+ .and_return(access_level)
+
+ allow(service)
+ .to receive(:merge_access_level)
+ .and_return(access_level)
+
+ allow(service)
+ .to receive(:default_branch)
+ .and_return('master')
+
+ allow(create_service)
+ .to receive(:execute)
+ .with(skip_authorization: true)
+
+ service.create_protected_branch
+
+ expect(create_service)
+ .to have_received(:execute)
+ end
+ end
+
+ describe '#protect_branch?' do
+ context 'when default branch protection is disabled' do
+ it 'returns false' do
+ allow(Gitlab::CurrentSettings)
+ .to receive(:default_branch_protection)
+ .and_return(Gitlab::Access::PROTECTION_NONE)
+
+ expect(service.protect_branch?).to eq(false)
+ end
+ end
+
+ context 'when default branch protection is enabled' do
+ before do
+ allow(Gitlab::CurrentSettings)
+ .to receive(:default_branch_protection)
+ .and_return(Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
+
+ allow(service)
+ .to receive(:default_branch)
+ .and_return('master')
+ end
+
+ it 'returns false if the branch is already protected' do
+ allow(ProtectedBranch)
+ .to receive(:protected?)
+ .with(project, 'master')
+ .and_return(true)
+
+ expect(service.protect_branch?).to eq(false)
+ end
+
+ it 'returns true if the branch is not yet protected' do
+ allow(ProtectedBranch)
+ .to receive(:protected?)
+ .with(project, 'master')
+ .and_return(false)
+
+ expect(service.protect_branch?).to eq(true)
+ end
+ end
+ end
+
+ describe '#default_branch' do
+ it 'returns the default branch of the project' do
+ allow(project)
+ .to receive(:default_branch)
+ .and_return('master')
+
+ expect(service.default_branch).to eq('master')
+ end
+ end
+
+ describe '#push_access_level' do
+ context 'when developers can push' do
+ it 'returns the DEVELOPER access level' do
+ allow(Gitlab::CurrentSettings)
+ .to receive(:default_branch_protection)
+ .and_return(Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
+
+ expect(service.push_access_level).to eq(Gitlab::Access::DEVELOPER)
+ end
+ end
+
+ context 'when developers can not push' do
+ it 'returns the MAINTAINER access level' do
+ allow(Gitlab::CurrentSettings)
+ .to receive(:default_branch_protection)
+ .and_return(Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
+
+ expect(service.push_access_level).to eq(Gitlab::Access::MAINTAINER)
+ end
+ end
+ end
+
+ describe '#merge_access_level' do
+ context 'when developers can merge' do
+ it 'returns the DEVELOPER access level' do
+ allow(Gitlab::CurrentSettings)
+ .to receive(:default_branch_protection)
+ .and_return(Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
+
+ expect(service.merge_access_level).to eq(Gitlab::Access::DEVELOPER)
+ end
+ end
+
+ context 'when developers can not merge' do
+ it 'returns the MAINTAINER access level' do
+ allow(Gitlab::CurrentSettings)
+ .to receive(:default_branch_protection)
+ .and_return(Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
+
+ expect(service.merge_access_level).to eq(Gitlab::Access::MAINTAINER)
+ end
+ end
+ end
+end