summaryrefslogtreecommitdiff
path: root/spec/models/project_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models/project_spec.rb')
-rw-r--r--spec/models/project_spec.rb638
1 files changed, 499 insertions, 139 deletions
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 4cf8d861595..a2f8fac2f38 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -63,7 +63,6 @@ describe Project do
it { is_expected.to have_many(:build_trace_section_names)}
it { is_expected.to have_many(:runner_projects) }
it { is_expected.to have_many(:runners) }
- it { is_expected.to have_many(:active_runners) }
it { is_expected.to have_many(:variables) }
it { is_expected.to have_many(:triggers) }
it { is_expected.to have_many(:pages_domains) }
@@ -77,13 +76,15 @@ describe Project do
it { is_expected.to have_many(:project_group_links) }
it { is_expected.to have_many(:notification_settings).dependent(:delete_all) }
it { is_expected.to have_many(:forks).through(:forked_project_links) }
- it { is_expected.to have_many(:uploads).dependent(:destroy) }
+ it { is_expected.to have_many(:uploads) }
it { is_expected.to have_many(:pipeline_schedules) }
it { is_expected.to have_many(:members_and_requesters) }
it { is_expected.to have_many(:clusters) }
it { is_expected.to have_many(:custom_attributes).class_name('ProjectCustomAttribute') }
it { is_expected.to have_many(:project_badges).class_name('ProjectBadge') }
it { is_expected.to have_many(:lfs_file_locks) }
+ it { is_expected.to have_many(:project_deploy_tokens) }
+ it { is_expected.to have_many(:deploy_tokens).through(:project_deploy_tokens) }
context 'after initialized' do
it "has a project_feature" do
@@ -91,6 +92,23 @@ describe Project do
end
end
+ context 'when creating a new project' do
+ it 'automatically creates a CI/CD settings row' do
+ project = create(:project)
+
+ expect(project.ci_cd_settings).to be_an_instance_of(ProjectCiCdSetting)
+ expect(project.ci_cd_settings).to be_persisted
+ end
+ end
+
+ context 'updating cd_cd_settings' do
+ it 'does not raise an error' do
+ project = create(:project)
+
+ expect { project.update(ci_cd_settings: nil) }.not_to raise_exception
+ end
+ end
+
describe '#members & #requesters' do
let(:project) { create(:project, :public, :access_requestable) }
let(:requester) { create(:user) }
@@ -220,18 +238,25 @@ describe Project do
expect(project2.import_data).to be_nil
end
- it "does not allow blocked import_url localhost" do
+ it "does not allow import_url pointing to localhost" do
project2 = build(:project, import_url: 'http://localhost:9000/t.git')
expect(project2).to be_invalid
- expect(project2.errors[:import_url]).to include('imports are not allowed from that URL')
+ expect(project2.errors[:import_url].first).to include('Requests to localhost are not allowed')
end
- it "does not allow blocked import_url port" do
+ it "does not allow import_url with invalid ports" do
project2 = build(:project, import_url: 'http://github.com:25/t.git')
expect(project2).to be_invalid
- expect(project2.errors[:import_url]).to include('imports are not allowed from that URL')
+ expect(project2.errors[:import_url].first).to include('Only allowed ports are 22, 80, 443')
+ end
+
+ it "does not allow import_url with invalid user" do
+ project2 = build(:project, import_url: 'http://$user:password@github.com/t.git')
+
+ expect(project2).to be_invalid
+ expect(project2.errors[:import_url].first).to include('Username needs to start with an alphanumeric character')
end
describe 'project pending deletion' do
@@ -291,12 +316,12 @@ describe Project do
describe 'project token' do
it 'sets an random token if none provided' do
- project = FactoryBot.create :project, runners_token: ''
+ project = FactoryBot.create(:project, runners_token: '')
expect(project.runners_token).not_to eq('')
end
it 'does not set an random token if one provided' do
- project = FactoryBot.create :project, runners_token: 'my-token'
+ project = FactoryBot.create(:project, runners_token: 'my-token')
expect(project.runners_token).to eq('my-token')
end
end
@@ -323,7 +348,7 @@ describe Project do
let(:owner) { create(:user, name: 'Gitlab') }
let(:namespace) { create(:namespace, path: 'sample-namespace', owner: owner) }
let(:project) { create(:project, path: 'sample-project', namespace: namespace) }
- let(:group) { create(:group, name: 'Group', path: 'sample-group', owner: owner) }
+ let(:group) { create(:group, name: 'Group', path: 'sample-group') }
context 'when nil argument' do
it 'returns nil' do
@@ -438,14 +463,6 @@ describe Project do
end
end
- describe '#repository_storage_path' do
- let(:project) { create(:project) }
-
- it 'returns the repository storage path' do
- expect(Dir.exist?(project.repository_storage_path)).to be(true)
- end
- end
-
it 'returns valid url to repo' do
project = described_class.new(path: 'somewhere')
expect(project.url_to_repo).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + 'somewhere.git')
@@ -459,6 +476,34 @@ describe Project do
end
end
+ describe "#readme_url" do
+ let(:project) { create(:project, :repository, path: "somewhere") }
+
+ context 'with a non-existing repository' do
+ it 'returns nil' do
+ allow(project.repository).to receive(:tree).with(:head).and_return(nil)
+
+ expect(project.readme_url).to be_nil
+ end
+ end
+
+ context 'with an existing repository' do
+ context 'when no README exists' do
+ it 'returns nil' do
+ allow_any_instance_of(Tree).to receive(:readme).and_return(nil)
+
+ expect(project.readme_url).to be_nil
+ end
+ end
+
+ context 'when a README exists' do
+ it 'returns the README' do
+ expect(project.readme_url).to eql("#{Gitlab.config.gitlab.url}/#{project.namespace.full_path}/somewhere/blob/master/README.md")
+ end
+ end
+ end
+ end
+
describe "#new_issuable_address" do
let(:project) { create(:project, path: "somewhere") }
let(:user) { create(:user) }
@@ -629,7 +674,7 @@ describe Project do
describe '#to_param' do
context 'with namespace' do
before do
- @group = create :group, name: 'gitlab'
+ @group = create(:group, name: 'gitlab')
@project = create(:project, name: 'gitlabhq', namespace: @group)
end
@@ -856,8 +901,8 @@ describe Project do
describe '#star_count' do
it 'counts stars from multiple users' do
- user1 = create :user
- user2 = create :user
+ user1 = create(:user)
+ user2 = create(:user)
project = create(:project, :public)
expect(project.star_count).to eq(0)
@@ -879,7 +924,7 @@ describe Project do
end
it 'counts stars on the right project' do
- user = create :user
+ user = create(:user)
project1 = create(:project, :public)
project2 = create(:project, :public)
@@ -922,7 +967,7 @@ describe Project do
it 'is false if avatar is html page' do
project.update_attribute(:avatar, 'uploads/avatar.html')
- expect(project.avatar_type).to eq(['only images allowed'])
+ expect(project.avatar_type).to eq(['file format is not supported. Please try one of the following supported formats: png, jpg, jpeg, gif, bmp, tiff, ico'])
end
end
@@ -1097,12 +1142,12 @@ describe Project do
end
context 'repository storage by default' do
- let(:project) { create(:project) }
+ let(:project) { build(:project) }
before do
storages = {
- 'default' => { 'path' => 'tmp/tests/repositories' },
- 'picked' => { 'path' => 'tmp/tests/repositories' }
+ 'default' => Gitlab::GitalyClient::StorageSettings.new('path' => 'tmp/tests/repositories'),
+ 'picked' => Gitlab::GitalyClient::StorageSettings.new('path' => 'tmp/tests/repositories')
}
allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
end
@@ -1136,51 +1181,112 @@ describe Project do
end
end
- describe '#any_runners' do
- let(:project) { create(:project, shared_runners_enabled: shared_runners_enabled) }
- let(:specific_runner) { create(:ci_runner) }
- let(:shared_runner) { create(:ci_runner, :shared) }
+ describe '#any_runners?' do
+ context 'shared runners' do
+ let(:project) { create(:project, shared_runners_enabled: shared_runners_enabled) }
+ let(:specific_runner) { create(:ci_runner, :project, projects: [project]) }
+ let(:shared_runner) { create(:ci_runner, :instance) }
- context 'for shared runners disabled' do
- let(:shared_runners_enabled) { false }
+ context 'for shared runners disabled' do
+ let(:shared_runners_enabled) { false }
- it 'has no runners available' do
- expect(project.any_runners?).to be_falsey
- end
+ it 'has no runners available' do
+ expect(project.any_runners?).to be_falsey
+ end
- it 'has a specific runner' do
- project.runners << specific_runner
- expect(project.any_runners?).to be_truthy
- end
+ it 'has a specific runner' do
+ specific_runner
+
+ expect(project.any_runners?).to be_truthy
+ end
- it 'has a shared runner, but they are prohibited to use' do
- shared_runner
- expect(project.any_runners?).to be_falsey
+ it 'has a shared runner, but they are prohibited to use' do
+ shared_runner
+
+ expect(project.any_runners?).to be_falsey
+ end
+
+ it 'checks the presence of specific runner' do
+ specific_runner
+
+ expect(project.any_runners? { |runner| runner == specific_runner }).to be_truthy
+ end
+
+ it 'returns false if match cannot be found' do
+ specific_runner
+
+ expect(project.any_runners? { false }).to be_falsey
+ end
end
- it 'checks the presence of specific runner' do
- project.runners << specific_runner
- expect(project.any_runners? { |runner| runner == specific_runner }).to be_truthy
+ context 'for shared runners enabled' do
+ let(:shared_runners_enabled) { true }
+
+ it 'has a shared runner' do
+ shared_runner
+
+ expect(project.any_runners?).to be_truthy
+ end
+
+ it 'checks the presence of shared runner' do
+ shared_runner
+
+ expect(project.any_runners? { |runner| runner == shared_runner }).to be_truthy
+ end
+
+ it 'returns false if match cannot be found' do
+ shared_runner
+
+ expect(project.any_runners? { false }).to be_falsey
+ end
end
end
- context 'for shared runners enabled' do
- let(:shared_runners_enabled) { true }
+ context 'group runners' do
+ let(:project) { create(:project, group_runners_enabled: group_runners_enabled) }
+ let(:group) { create(:group, projects: [project]) }
+ let(:group_runner) { create(:ci_runner, :group, groups: [group]) }
- it 'has a shared runner' do
- shared_runner
- expect(project.any_runners?).to be_truthy
+ context 'for group runners disabled' do
+ let(:group_runners_enabled) { false }
+
+ it 'has no runners available' do
+ expect(project.any_runners?).to be_falsey
+ end
+
+ it 'has a group runner, but they are prohibited to use' do
+ group_runner
+
+ expect(project.any_runners?).to be_falsey
+ end
end
- it 'checks the presence of shared runner' do
- shared_runner
- expect(project.any_runners? { |runner| runner == shared_runner }).to be_truthy
+ context 'for group runners enabled' do
+ let(:group_runners_enabled) { true }
+
+ it 'has a group runner' do
+ group_runner
+
+ expect(project.any_runners?).to be_truthy
+ end
+
+ it 'checks the presence of group runner' do
+ group_runner
+
+ expect(project.any_runners? { |runner| runner == group_runner }).to be_truthy
+ end
+
+ it 'returns false if match cannot be found' do
+ group_runner
+
+ expect(project.any_runners? { false }).to be_falsey
+ end
end
end
end
describe '#shared_runners' do
- let!(:runner) { create(:ci_runner, :shared) }
+ let!(:runner) { create(:ci_runner, :instance) }
subject { project.shared_runners }
@@ -1221,7 +1327,7 @@ describe Project do
end
describe '#pages_deployed?' do
- let(:project) { create :project }
+ let(:project) { create(:project) }
subject { project.pages_deployed? }
@@ -1239,8 +1345,8 @@ describe Project do
end
describe '#pages_url' do
- let(:group) { create :group, name: group_name }
- let(:project) { create :project, namespace: group, name: project_name }
+ let(:group) { create(:group, name: group_name) }
+ let(:project) { create(:project, namespace: group, name: project_name) }
let(:domain) { 'Example.com' }
subject { project.pages_url }
@@ -1265,6 +1371,34 @@ describe Project do
end
end
+ describe '#pages_group_url' do
+ let(:group) { create(:group, name: group_name) }
+ let(:project) { create(:project, namespace: group, name: project_name) }
+ let(:domain) { 'Example.com' }
+ let(:port) { 1234 }
+
+ subject { project.pages_group_url }
+
+ before do
+ allow(Settings.pages).to receive(:host).and_return(domain)
+ allow(Gitlab.config.pages).to receive(:url).and_return("http://example.com:#{port}")
+ end
+
+ context 'group page' do
+ let(:group_name) { 'Group' }
+ let(:project_name) { 'group.example.com' }
+
+ it { is_expected.to eq("http://group.example.com:#{port}") }
+ end
+
+ context 'project page' do
+ let(:group_name) { 'Group' }
+ let(:project_name) { 'Project' }
+
+ it { is_expected.to eq("http://group.example.com:#{port}") }
+ end
+ end
+
describe '.search' do
let(:project) { create(:project, description: 'kitten mittens') }
@@ -1356,8 +1490,8 @@ describe Project do
let(:private_group) { create(:group, visibility_level: 0) }
let(:internal_group) { create(:group, visibility_level: 10) }
- let(:private_project) { create :project, :private, group: private_group }
- let(:internal_project) { create :project, :internal, group: internal_group }
+ let(:private_project) { create(:project, :private, group: private_group) }
+ let(:internal_project) { create(:project, :internal, group: internal_group) }
context 'when group is private project can not be internal' do
it { expect(private_project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_falsey }
@@ -1422,7 +1556,7 @@ describe Project do
.and_return(false)
allow(shell).to receive(:create_repository)
- .with(project.repository_storage_path, project.disk_path)
+ .with(project.repository_storage, project.disk_path)
.and_return(true)
expect(project).to receive(:create_repository).with(force: true)
@@ -1453,52 +1587,6 @@ describe Project do
end
end
- describe '#user_can_push_to_empty_repo?' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
-
- it 'returns false when default_branch_protection is in full protection and user is developer' do
- project.add_developer(user)
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_FULL)
-
- expect(project.user_can_push_to_empty_repo?(user)).to be_falsey
- end
-
- it 'returns false when default_branch_protection only lets devs merge and user is dev' do
- project.add_developer(user)
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
-
- expect(project.user_can_push_to_empty_repo?(user)).to be_falsey
- end
-
- it 'returns true when default_branch_protection lets devs push and user is developer' do
- project.add_developer(user)
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
-
- expect(project.user_can_push_to_empty_repo?(user)).to be_truthy
- end
-
- it 'returns true when default_branch_protection is unprotected and user is developer' do
- project.add_developer(user)
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE)
-
- expect(project.user_can_push_to_empty_repo?(user)).to be_truthy
- end
-
- it 'returns true when user is master' do
- project.add_master(user)
-
- expect(project.user_can_push_to_empty_repo?(user)).to be_truthy
- end
-
- it 'returns false when the repo is not empty' do
- project.add_master(user)
- expect(project).to receive(:empty_repo?).and_return(false)
-
- expect(project.user_can_push_to_empty_repo?(user)).to be_falsey
- end
- end
-
describe '#container_registry_url' do
let(:project) { create(:project) }
@@ -1612,15 +1700,44 @@ describe Project do
end
end
+ describe '#human_import_status_name' do
+ context 'when import_state exists' do
+ it 'returns the humanized status name' do
+ project = create(:project)
+ create(:import_state, :started, project: project)
+
+ expect(project.human_import_status_name).to eq("started")
+ end
+ end
+
+ context 'when import_state was not created yet' do
+ let(:project) { create(:project, :import_started) }
+
+ it 'ensures import_state is created and returns humanized status name' do
+ expect do
+ project.human_import_status_name
+ end.to change { ProjectImportState.count }.from(0).to(1)
+ end
+
+ it 'returns humanized status name' do
+ expect(project.human_import_status_name).to eq("started")
+ end
+ end
+ end
+
describe 'Project import job' do
let(:project) { create(:project, import_url: generate(:url)) }
before do
allow_any_instance_of(Gitlab::Shell).to receive(:import_repository)
- .with(project.repository_storage_path, project.disk_path, project.import_url)
+ .with(project.repository_storage, project.disk_path, project.import_url)
.and_return(true)
- expect_any_instance_of(Repository).to receive(:after_import)
+ # Works around https://github.com/rspec/rspec-mocks/issues/910
+ allow(described_class).to receive(:find).with(project.id).and_return(project)
+ expect(project.repository).to receive(:after_import)
+ .and_call_original
+ expect(project.wiki.repository).to receive(:after_import)
.and_call_original
end
@@ -1650,7 +1767,8 @@ describe Project do
it 'resets project import_error' do
error_message = 'Some error'
- mirror = create(:project_empty_repo, :import_started, import_error: error_message)
+ mirror = create(:project_empty_repo, :import_started)
+ mirror.import_state.update_attributes(last_error: error_message)
expect { mirror.import_finish }.to change { mirror.import_error }.from(error_message).to(nil)
end
@@ -1770,10 +1888,7 @@ describe Project do
let(:project) { forked_project_link.forked_to_project }
it 'schedules a RepositoryForkWorker job' do
- expect(RepositoryForkWorker).to receive(:perform_async).with(
- project.id,
- forked_from_project.repository_storage_path,
- forked_from_project.disk_path).and_return(import_jid)
+ expect(RepositoryForkWorker).to receive(:perform_async).with(project.id).and_return(import_jid)
expect(project.add_import_job).to eq(import_jid)
end
@@ -1801,6 +1916,83 @@ describe Project do
it { expect(project.gitea_import?).to be true }
end
+ describe '#has_remote_mirror?' do
+ let(:project) { create(:project, :remote_mirror, :import_started) }
+ subject { project.has_remote_mirror? }
+
+ before do
+ allow_any_instance_of(RemoteMirror).to receive(:refresh_remote)
+ end
+
+ it 'returns true when a remote mirror is enabled' do
+ is_expected.to be_truthy
+ end
+
+ it 'returns false when remote mirror is disabled' do
+ project.remote_mirrors.first.update_attributes(enabled: false)
+
+ is_expected.to be_falsy
+ end
+ end
+
+ describe '#update_remote_mirrors' do
+ let(:project) { create(:project, :remote_mirror, :import_started) }
+ delegate :update_remote_mirrors, to: :project
+
+ before do
+ allow_any_instance_of(RemoteMirror).to receive(:refresh_remote)
+ end
+
+ it 'syncs enabled remote mirror' do
+ expect_any_instance_of(RemoteMirror).to receive(:sync)
+
+ update_remote_mirrors
+ end
+
+ it 'does nothing when remote mirror is disabled globally and not overridden' do
+ stub_application_setting(mirror_available: false)
+ project.remote_mirror_available_overridden = false
+
+ expect_any_instance_of(RemoteMirror).not_to receive(:sync)
+
+ update_remote_mirrors
+ end
+
+ it 'does not sync disabled remote mirrors' do
+ project.remote_mirrors.first.update_attributes(enabled: false)
+
+ expect_any_instance_of(RemoteMirror).not_to receive(:sync)
+
+ update_remote_mirrors
+ end
+ end
+
+ describe '#remote_mirror_available?' do
+ let(:project) { create(:project) }
+
+ context 'when remote mirror global setting is enabled' do
+ it 'returns true' do
+ expect(project.remote_mirror_available?).to be(true)
+ end
+ end
+
+ context 'when remote mirror global setting is disabled' do
+ before do
+ stub_application_setting(mirror_available: false)
+ end
+
+ it 'returns true when overridden' do
+ project.remote_mirror_available_overridden = true
+
+ expect(project.remote_mirror_available?).to be(true)
+ end
+
+ it 'returns false when not overridden' do
+ expect(project.remote_mirror_available?).to be(false)
+ end
+ end
+ end
+
describe '#ancestors_upto', :nested_groups do
let(:parent) { create(:group) }
let(:child) { create(:group, parent: parent) }
@@ -1997,6 +2189,22 @@ describe Project do
expect(forked_project.lfs_storage_project).to eq forked_project
end
end
+
+ describe '#all_lfs_objects' do
+ let(:lfs_object) { create(:lfs_object) }
+
+ before do
+ project.lfs_objects << lfs_object
+ end
+
+ it 'returns the lfs object for a project' do
+ expect(project.all_lfs_objects).to contain_exactly(lfs_object)
+ end
+
+ it 'returns the lfs object for a fork' do
+ expect(forked_project.all_lfs_objects).to contain_exactly(lfs_object)
+ end
+ end
end
describe '#pushes_since_gc' do
@@ -2131,6 +2339,22 @@ describe Project do
end
end
+ describe '#any_lfs_file_locks?', :request_store do
+ set(:project) { create(:project) }
+
+ it 'returns false when there are no LFS file locks' do
+ expect(project.any_lfs_file_locks?).to be_falsey
+ end
+
+ it 'returns a cached true when there are LFS file locks' do
+ create(:lfs_file_lock, project: project)
+
+ expect(project.lfs_file_locks).to receive(:any?).once.and_call_original
+
+ 2.times { expect(project.any_lfs_file_locks?).to be_truthy }
+ end
+ end
+
describe '#protected_for?' do
let(:project) { create(:project) }
@@ -2306,8 +2530,8 @@ describe Project do
end
describe '#pages_url' do
- let(:group) { create :group, name: 'Group' }
- let(:nested_group) { create :group, parent: group }
+ let(:group) { create(:group, name: 'Group') }
+ let(:nested_group) { create(:group, parent: group) }
let(:domain) { 'Example.com' }
subject { project.pages_url }
@@ -2318,7 +2542,7 @@ describe Project do
end
context 'top-level group' do
- let(:project) { create :project, namespace: group, name: project_name }
+ let(:project) { create(:project, namespace: group, name: project_name) }
context 'group page' do
let(:project_name) { 'group.example.com' }
@@ -2334,7 +2558,7 @@ describe Project do
end
context 'nested group' do
- let(:project) { create :project, namespace: nested_group, name: project_name }
+ let(:project) { create(:project, namespace: nested_group, name: project_name) }
let(:expected_url) { "http://group.example.com/#{nested_group.path}/#{project.path}" }
context 'group page' do
@@ -2352,7 +2576,7 @@ describe Project do
end
describe '#http_url_to_repo' do
- let(:project) { create :project }
+ let(:project) { create(:project) }
it 'returns the url to the repo without a username' do
expect(project.http_url_to_repo).to eq("#{project.web_url}.git")
@@ -2532,7 +2756,7 @@ describe Project do
end
end
- describe '#remove_exports' do
+ describe '#remove_export' do
let(:legacy_project) { create(:project, :legacy_storage, :with_export) }
let(:project) { create(:project, :with_export) }
@@ -2580,6 +2804,23 @@ describe Project do
end
end
+ describe '#remove_exported_project_file' do
+ let(:project) { create(:project, :with_export) }
+
+ it 'removes the exported project file' do
+ exported_file = project.export_project_path
+
+ expect(File.exist?(exported_file)).to be_truthy
+
+ allow(FileUtils).to receive(:rm_f).and_call_original
+ expect(FileUtils).to receive(:rm_f).with(exported_file).and_call_original
+
+ project.remove_exported_project_file
+
+ expect(File.exist?(exported_file)).to be_falsy
+ end
+ end
+
describe '#forks_count' do
it 'returns the number of forks' do
project = build(:project)
@@ -2613,7 +2854,7 @@ describe Project do
describe '#ensure_storage_path_exists' do
it 'delegates to gitlab_shell to ensure namespace is created' do
- expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage_path, project.base_dir)
+ expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage, project.base_dir)
project.ensure_storage_path_exists
end
@@ -2652,12 +2893,12 @@ describe Project do
expect(gitlab_shell).to receive(:mv_repository)
.ordered
- .with(project.repository_storage_path, "#{project.namespace.full_path}/foo", "#{project.full_path}")
+ .with(project.repository_storage, "#{project.namespace.full_path}/foo", "#{project.full_path}")
.and_return(true)
expect(gitlab_shell).to receive(:mv_repository)
.ordered
- .with(project.repository_storage_path, "#{project.namespace.full_path}/foo.wiki", "#{project.full_path}.wiki")
+ .with(project.repository_storage, "#{project.namespace.full_path}/foo.wiki", "#{project.full_path}.wiki")
.and_return(true)
expect_any_instance_of(SystemHooksService)
@@ -2718,7 +2959,7 @@ describe Project do
project.rename_repo
- expect(project.repository.rugged.config['gitlab.fullpath']).to eq(project.full_path)
+ expect(rugged_config['gitlab.fullpath']).to eq(project.full_path)
end
end
@@ -2806,7 +3047,7 @@ describe Project do
it 'delegates to gitlab_shell to ensure namespace is created' do
allow(project).to receive(:gitlab_shell).and_return(gitlab_shell)
- expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage_path, hashed_prefix)
+ expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage, hashed_prefix)
project.ensure_storage_path_exists
end
@@ -2879,7 +3120,7 @@ describe Project do
it 'updates project full path in .git/config' do
project.rename_repo
- expect(project.repository.rugged.config['gitlab.fullpath']).to eq(project.full_path)
+ expect(rugged_config['gitlab.fullpath']).to eq(project.full_path)
end
end
@@ -3177,14 +3418,16 @@ describe Project do
end
describe '#after_import' do
- let(:project) { build(:project) }
+ let(:project) { create(:project) }
it 'runs the correct hooks' do
expect(project.repository).to receive(:after_import)
+ expect(project.wiki.repository).to receive(:after_import)
expect(project).to receive(:import_finish)
expect(project).to receive(:update_project_counter_caches)
expect(project).to receive(:remove_import_jid)
expect(project).to receive(:after_create_default_branch)
+ expect(project).to receive(:refresh_markdown_cache!)
project.after_import
end
@@ -3263,7 +3506,8 @@ describe Project do
context 'with an import JID' do
it 'unsets the import JID' do
- project = create(:project, import_jid: '123')
+ project = create(:project)
+ create(:import_state, project: project, jid: '123')
expect(Gitlab::SidekiqStatus)
.to receive(:unset)
@@ -3297,13 +3541,13 @@ describe Project do
it 'writes full path in .git/config when key is missing' do
project.write_repository_config
- expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path
+ expect(rugged_config['gitlab.fullpath']).to eq project.full_path
end
it 'updates full path in .git/config when key is present' do
project.write_repository_config(gl_full_path: 'old/path')
- expect { project.write_repository_config }.to change { project.repository.rugged.config['gitlab.fullpath'] }.from('old/path').to(project.full_path)
+ expect { project.write_repository_config }.to change { rugged_config['gitlab.fullpath'] }.from('old/path').to(project.full_path)
end
it 'does not raise an error with an empty repository' do
@@ -3392,7 +3636,7 @@ describe Project do
target_branch: 'target-branch',
source_project: project,
source_branch: 'awesome-feature-1',
- allow_maintainer_to_push: true
+ allow_collaboration: true
)
end
@@ -3429,9 +3673,14 @@ describe Project do
end
end
- describe '#branch_allows_maintainer_push?' do
+ describe '#branch_allows_collaboration_push?' do
it 'allows access if the user can merge the merge request' do
- expect(project.branch_allows_maintainer_push?(user, 'awesome-feature-1'))
+ expect(project.branch_allows_collaboration?(user, 'awesome-feature-1'))
+ .to be_truthy
+ end
+
+ it 'allows access when there are merge requests open but no branch name is given' do
+ expect(project.branch_allows_collaboration?(user, nil))
.to be_truthy
end
@@ -3439,7 +3688,7 @@ describe Project do
guest = create(:user)
target_project.add_guest(guest)
- expect(project.branch_allows_maintainer_push?(guest, 'awesome-feature-1'))
+ expect(project.branch_allows_collaboration?(guest, 'awesome-feature-1'))
.to be_falsy
end
@@ -3449,34 +3698,145 @@ describe Project do
target_branch: 'target-branch',
source_project: project,
source_branch: 'rejected-feature-1',
- allow_maintainer_to_push: true)
+ allow_collaboration: true)
- expect(project.branch_allows_maintainer_push?(user, 'rejected-feature-1'))
+ expect(project.branch_allows_collaboration?(user, 'rejected-feature-1'))
.to be_falsy
end
it 'does not allow access if the user cannot merge the merge request' do
create(:protected_branch, :masters_can_push, project: target_project, name: 'target-branch')
- expect(project.branch_allows_maintainer_push?(user, 'awesome-feature-1'))
+ expect(project.branch_allows_collaboration?(user, 'awesome-feature-1'))
.to be_falsy
end
it 'caches the result' do
- control = ActiveRecord::QueryRecorder.new { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') }
+ control = ActiveRecord::QueryRecorder.new { project.branch_allows_collaboration?(user, 'awesome-feature-1') }
- expect { 3.times { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') } }
+ expect { 3.times { project.branch_allows_collaboration?(user, 'awesome-feature-1') } }
.not_to exceed_query_limit(control)
end
context 'when the requeststore is active', :request_store do
it 'only queries per project across instances' do
- control = ActiveRecord::QueryRecorder.new { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') }
+ control = ActiveRecord::QueryRecorder.new { project.branch_allows_collaboration?(user, 'awesome-feature-1') }
- expect { 2.times { described_class.find(project.id).branch_allows_maintainer_push?(user, 'awesome-feature-1') } }
+ expect { 2.times { described_class.find(project.id).branch_allows_collaboration?(user, 'awesome-feature-1') } }
.not_to exceed_query_limit(control).with_threshold(2)
end
end
end
end
+
+ describe "#pages_https_only?" do
+ subject { build(:project) }
+
+ context "when HTTPS pages are disabled" do
+ it { is_expected.not_to be_pages_https_only }
+ end
+
+ context "when HTTPS pages are enabled", :https_pages_enabled do
+ it { is_expected.to be_pages_https_only }
+ end
+ end
+
+ describe "#pages_https_only? validation", :https_pages_enabled do
+ subject(:project) do
+ # set-up dirty object:
+ create(:project, pages_https_only: false).tap do |p|
+ p.pages_https_only = true
+ end
+ end
+
+ context "when no domains are associated" do
+ it { is_expected.to be_valid }
+ end
+
+ context "when domains including keys and certificates are associated" do
+ before do
+ allow(project)
+ .to receive(:pages_domains)
+ .and_return([instance_double(PagesDomain, https?: true)])
+ end
+
+ it { is_expected.to be_valid }
+ end
+
+ context "when domains including no keys or certificates are associated" do
+ before do
+ allow(project)
+ .to receive(:pages_domains)
+ .and_return([instance_double(PagesDomain, https?: false)])
+ end
+
+ it { is_expected.not_to be_valid }
+ end
+ end
+
+ describe '#toggle_ci_cd_settings!' do
+ it 'toggles the value on #settings' do
+ project = create(:project, group_runners_enabled: false)
+
+ expect(project.group_runners_enabled).to be false
+
+ project.toggle_ci_cd_settings!(:group_runners_enabled)
+
+ expect(project.group_runners_enabled).to be true
+ end
+ end
+
+ describe '#gitlab_deploy_token' do
+ let(:project) { create(:project) }
+
+ subject { project.gitlab_deploy_token }
+
+ context 'when there is a gitlab deploy token associated' do
+ let!(:deploy_token) { create(:deploy_token, :gitlab_deploy_token, projects: [project]) }
+
+ it { is_expected.to eq(deploy_token) }
+ end
+
+ context 'when there is no a gitlab deploy token associated' do
+ it { is_expected.to be_nil }
+ end
+
+ context 'when there is a gitlab deploy token associated but is has been revoked' do
+ let!(:deploy_token) { create(:deploy_token, :gitlab_deploy_token, :revoked, projects: [project]) }
+ it { is_expected.to be_nil }
+ end
+
+ context 'when there is a gitlab deploy token associated but it is expired' do
+ let!(:deploy_token) { create(:deploy_token, :gitlab_deploy_token, :expired, projects: [project]) }
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'when there is a deploy token associated with a different name' do
+ let!(:deploy_token) { create(:deploy_token, projects: [project]) }
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'when there is a deploy token associated to a different project' do
+ let(:project_2) { create(:project) }
+ let!(:deploy_token) { create(:deploy_token, projects: [project_2]) }
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ context 'with uploads' do
+ it_behaves_like 'model with mounted uploader', true do
+ let(:model_object) { create(:project, :with_avatar) }
+ let(:upload_attribute) { :avatar }
+ let(:uploader_class) { AttachmentUploader }
+ end
+ end
+
+ def rugged_config
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ project.repository.rugged.config
+ end
+ end
end