debian-mirror-gitlab/spec/models/project_spec.rb

6501 lines
200 KiB
Ruby
Raw Normal View History

2019-07-07 11:18:12 +05:30
# frozen_string_literal: true
2014-09-02 18:07:02 +05:30
require 'spec_helper'
2020-07-28 23:09:34 +05:30
RSpec.describe Project do
2018-03-27 19:54:05 +05:30
include ProjectForksHelper
2018-12-05 23:21:45 +05:30
include GitHelpers
2019-07-07 11:18:12 +05:30
include ExternalAuthorizationServiceHelpers
2020-05-24 23:13:21 +05:30
using RSpec::Parameterized::TableSyntax
2018-03-27 19:54:05 +05:30
2019-02-15 15:39:39 +05:30
it_behaves_like 'having unique enum values'
2015-09-11 14:41:01 +05:30
describe 'associations' do
2015-04-26 12:48:37 +05:30
it { is_expected.to belong_to(:group) }
it { is_expected.to belong_to(:namespace) }
it { is_expected.to belong_to(:creator).class_name('User') }
2018-12-13 13:39:08 +05:30
it { is_expected.to belong_to(:pool_repository) }
2015-04-26 12:48:37 +05:30
it { is_expected.to have_many(:users) }
2016-09-29 09:46:39 +05:30
it { is_expected.to have_many(:services) }
2017-09-10 17:25:29 +05:30
it { is_expected.to have_many(:events) }
it { is_expected.to have_many(:merge_requests) }
it { is_expected.to have_many(:issues) }
it { is_expected.to have_many(:milestones) }
2020-05-24 23:13:21 +05:30
it { is_expected.to have_many(:iterations) }
2017-09-10 17:25:29 +05:30
it { is_expected.to have_many(:project_members).dependent(:delete_all) }
2016-08-24 12:49:21 +05:30
it { is_expected.to have_many(:users).through(:project_members) }
2017-09-10 17:25:29 +05:30
it { is_expected.to have_many(:requesters).dependent(:delete_all) }
it { is_expected.to have_many(:notes) }
it { is_expected.to have_many(:snippets).class_name('ProjectSnippet') }
it { is_expected.to have_many(:deploy_keys_projects) }
2015-04-26 12:48:37 +05:30
it { is_expected.to have_many(:deploy_keys) }
2017-09-10 17:25:29 +05:30
it { is_expected.to have_many(:hooks) }
it { is_expected.to have_many(:protected_branches) }
it { is_expected.to have_one(:slack_service) }
it { is_expected.to have_one(:microsoft_teams_service) }
it { is_expected.to have_one(:mattermost_service) }
2018-11-18 11:00:15 +05:30
it { is_expected.to have_one(:hangouts_chat_service) }
2020-01-01 13:55:28 +05:30
it { is_expected.to have_one(:unify_circuit_service) }
2020-05-24 23:13:21 +05:30
it { is_expected.to have_one(:webex_teams_service) }
2018-03-17 18:26:18 +05:30
it { is_expected.to have_one(:packagist_service) }
2017-09-10 17:25:29 +05:30
it { is_expected.to have_one(:pushover_service) }
it { is_expected.to have_one(:asana_service) }
it { is_expected.to have_many(:boards) }
it { is_expected.to have_one(:campfire_service) }
2019-02-15 15:39:39 +05:30
it { is_expected.to have_one(:discord_service) }
2017-09-10 17:25:29 +05:30
it { is_expected.to have_one(:drone_ci_service) }
it { is_expected.to have_one(:emails_on_push_service) }
it { is_expected.to have_one(:pipelines_email_service) }
it { is_expected.to have_one(:irker_service) }
it { is_expected.to have_one(:pivotaltracker_service) }
it { is_expected.to have_one(:hipchat_service) }
it { is_expected.to have_one(:flowdock_service) }
it { is_expected.to have_one(:assembla_service) }
it { is_expected.to have_one(:slack_slash_commands_service) }
it { is_expected.to have_one(:mattermost_slash_commands_service) }
it { is_expected.to have_one(:buildkite_service) }
it { is_expected.to have_one(:bamboo_service) }
it { is_expected.to have_one(:teamcity_service) }
it { is_expected.to have_one(:jira_service) }
it { is_expected.to have_one(:redmine_service) }
2019-07-07 11:18:12 +05:30
it { is_expected.to have_one(:youtrack_service) }
2017-09-10 17:25:29 +05:30
it { is_expected.to have_one(:custom_issue_tracker_service) }
it { is_expected.to have_one(:bugzilla_service) }
it { is_expected.to have_one(:external_wiki_service) }
2020-07-28 23:09:34 +05:30
it { is_expected.to have_one(:confluence_service) }
2017-09-10 17:25:29 +05:30
it { is_expected.to have_one(:project_feature) }
2019-02-15 15:39:39 +05:30
it { is_expected.to have_one(:project_repository) }
2020-01-01 13:55:28 +05:30
it { is_expected.to have_one(:container_expiration_policy) }
2017-09-10 17:25:29 +05:30
it { is_expected.to have_one(:statistics).class_name('ProjectStatistics') }
it { is_expected.to have_one(:import_data).class_name('ProjectImportData') }
2016-09-29 09:46:39 +05:30
it { is_expected.to have_one(:last_event).class_name('Event') }
2018-12-13 13:39:08 +05:30
it { is_expected.to have_one(:forked_from_project).through(:fork_network_member) }
2018-03-17 18:26:18 +05:30
it { is_expected.to have_one(:auto_devops).class_name('ProjectAutoDevops') }
2019-02-15 15:39:39 +05:30
it { is_expected.to have_one(:error_tracking_setting).class_name('ErrorTracking::ProjectErrorTrackingSetting') }
2020-03-13 15:44:24 +05:30
it { is_expected.to have_one(:project_setting) }
2020-04-22 19:07:51 +05:30
it { is_expected.to have_one(:alerting_setting).class_name('Alerting::ProjectAlertingSetting') }
2015-12-23 02:04:40 +05:30
it { is_expected.to have_many(:commit_statuses) }
2019-02-15 15:39:39 +05:30
it { is_expected.to have_many(:ci_pipelines) }
2020-04-08 14:13:33 +05:30
it { is_expected.to have_many(:ci_refs) }
2015-12-23 02:04:40 +05:30
it { is_expected.to have_many(:builds) }
2018-03-17 18:26:18 +05:30
it { is_expected.to have_many(:build_trace_section_names)}
2020-06-23 00:09:42 +05:30
it { is_expected.to have_many(:build_report_results) }
2015-12-23 02:04:40 +05:30
it { is_expected.to have_many(:runner_projects) }
it { is_expected.to have_many(:runners) }
it { is_expected.to have_many(:variables) }
it { is_expected.to have_many(:triggers) }
2017-08-17 22:00:37 +05:30
it { is_expected.to have_many(:pages_domains) }
2017-09-10 17:25:29 +05:30
it { is_expected.to have_many(:labels).class_name('ProjectLabel') }
it { is_expected.to have_many(:users_star_projects) }
2018-11-18 11:00:15 +05:30
it { is_expected.to have_many(:repository_languages) }
2017-09-10 17:25:29 +05:30
it { is_expected.to have_many(:environments) }
it { is_expected.to have_many(:deployments) }
it { is_expected.to have_many(:todos) }
it { is_expected.to have_many(:releases) }
it { is_expected.to have_many(:lfs_objects_projects) }
it { is_expected.to have_many(:project_group_links) }
it { is_expected.to have_many(:notification_settings).dependent(:delete_all) }
2018-12-13 13:39:08 +05:30
it { is_expected.to have_many(:forked_to_members).class_name('ForkNetworkMember') }
it { is_expected.to have_many(:forks).through(:forked_to_members) }
2018-11-08 19:23:39 +05:30
it { is_expected.to have_many(:uploads) }
2017-09-10 17:25:29 +05:30
it { is_expected.to have_many(:pipeline_schedules) }
2018-03-17 18:26:18 +05:30
it { is_expected.to have_many(:members_and_requesters) }
it { is_expected.to have_many(:clusters) }
2019-12-21 20:55:43 +05:30
it { is_expected.to have_many(:management_clusters).class_name('Clusters::Cluster') }
2019-02-15 15:39:39 +05:30
it { is_expected.to have_many(:kubernetes_namespaces) }
2020-10-24 23:57:45 +05:30
it { is_expected.to have_many(:cluster_agents).class_name('Clusters::Agent') }
2018-03-17 18:26:18 +05:30
it { is_expected.to have_many(:custom_attributes).class_name('ProjectCustomAttribute') }
2018-03-27 19:54:05 +05:30
it { is_expected.to have_many(:project_badges).class_name('ProjectBadge') }
2018-03-17 18:26:18 +05:30
it { is_expected.to have_many(:lfs_file_locks) }
2018-05-09 12:01:36 +05:30
it { is_expected.to have_many(:project_deploy_tokens) }
it { is_expected.to have_many(:deploy_tokens).through(:project_deploy_tokens) }
2019-10-12 21:52:04 +05:30
it { is_expected.to have_many(:cycle_analytics_stages) }
2019-12-04 20:38:33 +05:30
it { is_expected.to have_many(:external_pull_requests) }
2019-12-21 20:55:43 +05:30
it { is_expected.to have_many(:sourced_pipelines) }
it { is_expected.to have_many(:source_pipelines) }
2020-04-22 19:07:51 +05:30
it { is_expected.to have_many(:prometheus_alert_events) }
it { is_expected.to have_many(:self_managed_prometheus_alert_events) }
2020-05-24 23:13:21 +05:30
it { is_expected.to have_many(:alert_management_alerts) }
2020-04-22 19:07:51 +05:30
it { is_expected.to have_many(:jira_imports) }
2020-05-24 23:13:21 +05:30
it { is_expected.to have_many(:metrics_users_starred_dashboards).inverse_of(:project) }
it { is_expected.to have_many(:repository_storage_moves) }
2020-06-23 00:09:42 +05:30
it { is_expected.to have_many(:reviews).inverse_of(:project) }
2020-07-28 23:09:34 +05:30
it { is_expected.to have_many(:packages).class_name('Packages::Package') }
it { is_expected.to have_many(:package_files).class_name('Packages::PackageFile') }
2020-10-24 23:57:45 +05:30
it { is_expected.to have_many(:pipeline_artifacts) }
2016-08-24 12:49:21 +05:30
2020-03-13 15:44:24 +05:30
it_behaves_like 'model with repository' do
let_it_be(:container) { create(:project, :repository, path: 'somewhere') }
let(:stubbed_container) { build_stubbed(:project) }
let(:expected_full_path) { "#{container.namespace.full_path}/somewhere" }
end
2020-05-24 23:13:21 +05:30
it_behaves_like 'model with wiki' do
let(:container) { create(:project, :wiki_repo) }
let(:container_without_wiki) { create(:project) }
end
2018-12-13 13:39:08 +05:30
it 'has an inverse relationship with merge requests' do
expect(described_class.reflect_on_association(:merge_requests).has_inverse?).to eq(:target_project)
end
2019-09-04 21:01:54 +05:30
it 'has a distinct has_many :lfs_objects relation through lfs_objects_projects' do
project = create(:project)
lfs_object = create(:lfs_object)
[:project, :design].each do |repository_type|
create(:lfs_objects_project, project: project,
lfs_object: lfs_object,
repository_type: repository_type)
end
expect(project.lfs_objects_projects.size).to eq(2)
expect(project.lfs_objects.size).to eq(1)
expect(project.lfs_objects.to_a).to eql([lfs_object])
end
2016-11-24 13:41:30 +05:30
context 'after initialized' do
it "has a project_feature" do
2017-09-10 17:25:29 +05:30
expect(described_class.new.project_feature).to be_present
2016-11-03 12:29:30 +05:30
end
end
2018-10-15 14:42:47 +05:30
context 'when creating a new project' do
2020-03-13 15:44:24 +05:30
let_it_be(:project) { create(:project) }
2018-10-15 14:42:47 +05:30
2020-03-13 15:44:24 +05:30
it 'automatically creates a CI/CD settings row' do
2018-10-15 14:42:47 +05:30
expect(project.ci_cd_settings).to be_an_instance_of(ProjectCiCdSetting)
expect(project.ci_cd_settings).to be_persisted
end
2019-12-21 20:55:43 +05:30
2020-01-01 13:55:28 +05:30
it 'automatically creates a container expiration policy row' do
expect(project.container_expiration_policy).to be_an_instance_of(ContainerExpirationPolicy)
expect(project.container_expiration_policy).to be_persisted
end
2020-03-13 15:44:24 +05:30
it 'does not create another container expiration policy if there is already one' do
project = build(:project)
expect do
container_expiration_policy = create(:container_expiration_policy, project: project)
expect(project.container_expiration_policy).to eq(container_expiration_policy)
end.to change { ContainerExpirationPolicy.count }.by(1)
end
2019-12-21 20:55:43 +05:30
2020-03-13 15:44:24 +05:30
it 'automatically creates a Pages metadata row' do
2019-12-21 20:55:43 +05:30
expect(project.pages_metadatum).to be_an_instance_of(ProjectPagesMetadatum)
expect(project.pages_metadatum).to be_persisted
end
2020-03-13 15:44:24 +05:30
2020-06-23 00:09:42 +05:30
it 'automatically builds a project setting row' do
2020-03-13 15:44:24 +05:30
expect(project.project_setting).to be_an_instance_of(ProjectSetting)
2020-06-23 00:09:42 +05:30
expect(project.project_setting).to be_new_record
2020-03-13 15:44:24 +05:30
end
2018-10-15 14:42:47 +05:30
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
2016-08-24 12:49:21 +05:30
describe '#members & #requesters' do
2019-12-21 20:55:43 +05:30
let(:project) { create(:project, :public) }
2016-08-24 12:49:21 +05:30
let(:requester) { create(:user) }
let(:developer) { create(:user) }
2020-03-13 15:44:24 +05:30
2016-08-24 12:49:21 +05:30
before do
project.request_access(requester)
2018-03-17 18:26:18 +05:30
project.add_developer(developer)
2016-08-24 12:49:21 +05:30
end
2018-03-17 18:26:18 +05:30
it_behaves_like 'members and requesters associations' do
let(:namespace) { project }
2016-08-24 12:49:21 +05:30
end
end
2016-11-03 12:29:30 +05:30
2019-02-15 15:39:39 +05:30
describe 'ci_pipelines association' do
it 'returns only pipelines from ci_sources' do
expect(Ci::Pipeline).to receive(:ci_sources).and_call_original
subject.ci_pipelines
end
end
2014-09-02 18:07:02 +05:30
end
2015-09-11 14:41:01 +05:30
describe 'modules' do
subject { described_class }
it { is_expected.to include_module(Gitlab::ConfigHelper) }
it { is_expected.to include_module(Gitlab::ShellAdapter) }
it { is_expected.to include_module(Gitlab::VisibilityLevel) }
it { is_expected.to include_module(Referable) }
it { is_expected.to include_module(Sortable) }
2014-09-02 18:07:02 +05:30
end
2015-09-11 14:41:01 +05:30
describe 'validation' do
2017-09-10 17:25:29 +05:30
let!(:project) { create(:project) }
2014-09-02 18:07:02 +05:30
2015-04-26 12:48:37 +05:30
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_uniqueness_of(:name).scoped_to(:namespace_id) }
2017-08-17 22:00:37 +05:30
it { is_expected.to validate_length_of(:name).is_at_most(255) }
2015-04-26 12:48:37 +05:30
it { is_expected.to validate_presence_of(:path) }
2017-08-17 22:00:37 +05:30
it { is_expected.to validate_length_of(:path).is_at_most(255) }
it { is_expected.to validate_length_of(:description).is_at_most(2000) }
2017-09-10 17:25:29 +05:30
it { is_expected.to validate_length_of(:ci_config_path).is_at_most(255) }
it { is_expected.to allow_value('').for(:ci_config_path) }
it { is_expected.not_to allow_value('test/../foo').for(:ci_config_path) }
2018-03-17 18:26:18 +05:30
it { is_expected.not_to allow_value('/test/foo').for(:ci_config_path) }
2015-04-26 12:48:37 +05:30
it { is_expected.to validate_presence_of(:creator) }
it { is_expected.to validate_presence_of(:namespace) }
2016-08-24 12:49:21 +05:30
it { is_expected.to validate_presence_of(:repository_storage) }
2020-03-13 15:44:24 +05:30
it { is_expected.to validate_numericality_of(:max_artifacts_size).only_integer.is_greater_than(0) }
2014-09-02 18:07:02 +05:30
2018-11-18 11:00:15 +05:30
it 'validates build timeout constraints' do
is_expected.to validate_numericality_of(:build_timeout)
.only_integer
.is_greater_than_or_equal_to(10.minutes)
.is_less_than(1.month)
2019-09-30 21:07:59 +05:30
.with_message('needs to be between 10 minutes and 1 month')
2018-11-18 11:00:15 +05:30
end
2016-09-13 17:45:13 +05:30
it 'does not allow new projects beyond user limits' do
2017-09-10 17:25:29 +05:30
project2 = build(:project)
2019-03-02 22:35:43 +05:30
allow(project2)
.to receive(:creator)
.and_return(
double(can_create_project?: false, projects_limit: 0).as_null_object
)
2015-04-26 12:48:37 +05:30
expect(project2).not_to be_valid
2014-09-02 18:07:02 +05:30
end
2016-08-24 12:49:21 +05:30
2019-06-05 12:25:43 +05:30
it 'validates the visibility' do
expect_any_instance_of(described_class).to receive(:visibility_level_allowed_as_fork).and_call_original
expect_any_instance_of(described_class).to receive(:visibility_level_allowed_by_group).and_call_original
create(:project)
end
2017-09-10 17:25:29 +05:30
context 'repository storages inclusion' do
let(:project2) { build(:project, repository_storage: 'missing') }
2016-08-24 12:49:21 +05:30
before do
2017-08-17 22:00:37 +05:30
storages = { 'custom' => { 'path' => 'tmp/tests/custom_repositories' } }
2016-08-24 12:49:21 +05:30
allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
end
2016-09-13 17:45:13 +05:30
it "does not allow repository storages that don't match a label in the configuration" do
2016-08-24 12:49:21 +05:30
expect(project2).not_to be_valid
expect(project2.errors[:repository_storage].first).to match(/is not included in the list/)
end
end
2020-03-13 15:44:24 +05:30
it 'validates presence of project_feature' do
project = build(:project, project_feature: nil)
expect(project).not_to be_valid
end
2018-11-29 20:51:05 +05:30
describe 'import_url' do
it 'does not allow an invalid URI as import_url' do
2018-12-13 13:39:08 +05:30
project = build(:project, import_url: 'invalid://')
2016-08-24 12:49:21 +05:30
2018-12-13 13:39:08 +05:30
expect(project).not_to be_valid
end
it 'does allow a SSH URI as import_url for persisted projects' do
project = create(:project)
project.import_url = 'ssh://test@gitlab.com/project.git'
expect(project).to be_valid
end
it 'does not allow a SSH URI as import_url for new projects' do
project = build(:project, import_url: 'ssh://test@gitlab.com/project.git')
expect(project).not_to be_valid
2018-11-29 20:51:05 +05:30
end
2016-08-24 12:49:21 +05:30
2018-11-29 20:51:05 +05:30
it 'does allow a valid URI as import_url' do
2018-12-13 13:39:08 +05:30
project = build(:project, import_url: 'http://gitlab.com/project.git')
2016-08-24 12:49:21 +05:30
2018-12-13 13:39:08 +05:30
expect(project).to be_valid
2018-11-29 20:51:05 +05:30
end
2016-08-24 12:49:21 +05:30
2018-11-29 20:51:05 +05:30
it 'allows an empty URI' do
2018-12-13 13:39:08 +05:30
project = build(:project, import_url: '')
2016-08-24 12:49:21 +05:30
2018-12-13 13:39:08 +05:30
expect(project).to be_valid
2018-11-29 20:51:05 +05:30
end
2016-08-24 12:49:21 +05:30
2018-11-29 20:51:05 +05:30
it 'does not produce import data on an empty URI' do
2018-12-13 13:39:08 +05:30
project = build(:project, import_url: '')
2016-08-24 12:49:21 +05:30
2018-12-13 13:39:08 +05:30
expect(project.import_data).to be_nil
2018-11-29 20:51:05 +05:30
end
2016-08-24 12:49:21 +05:30
2018-11-29 20:51:05 +05:30
it 'does not produce import data on an invalid URI' do
2018-12-13 13:39:08 +05:30
project = build(:project, import_url: 'test://')
2016-08-24 12:49:21 +05:30
2018-12-13 13:39:08 +05:30
expect(project.import_data).to be_nil
2018-11-29 20:51:05 +05:30
end
2017-08-17 22:00:37 +05:30
2018-11-29 20:51:05 +05:30
it "does not allow import_url pointing to localhost" do
2018-12-13 13:39:08 +05:30
project = build(:project, import_url: 'http://localhost:9000/t.git')
expect(project).to be_invalid
expect(project.errors[:import_url].first).to include('Requests to localhost are not allowed')
end
2017-08-17 22:00:37 +05:30
2019-01-03 12:48:30 +05:30
it 'does not allow import_url pointing to the local network' do
project = build(:project, import_url: 'https://192.168.1.1')
expect(project).to be_invalid
expect(project.errors[:import_url].first).to include('Requests to the local network are not allowed')
end
2018-12-13 13:39:08 +05:30
it "does not allow import_url with invalid ports for new projects" do
project = build(:project, import_url: 'http://github.com:25/t.git')
expect(project).to be_invalid
expect(project.errors[:import_url].first).to include('Only allowed ports are 80, 443')
2018-11-29 20:51:05 +05:30
end
2017-08-17 22:00:37 +05:30
2018-12-13 13:39:08 +05:30
it "does not allow import_url with invalid ports for persisted projects" do
project = create(:project)
project.import_url = 'http://github.com:25/t.git'
2017-08-17 22:00:37 +05:30
2018-12-13 13:39:08 +05:30
expect(project).to be_invalid
expect(project.errors[:import_url].first).to include('Only allowed ports are 22, 80, 443')
2018-11-29 20:51:05 +05:30
end
it "does not allow import_url with invalid user" do
2018-12-13 13:39:08 +05:30
project = build(:project, import_url: 'http://$user:password@github.com/t.git')
2017-08-17 22:00:37 +05:30
2018-12-13 13:39:08 +05:30
expect(project).to be_invalid
expect(project.errors[:import_url].first).to include('Username needs to start with an alphanumeric character')
2018-11-29 20:51:05 +05:30
end
2018-11-08 19:23:39 +05:30
2018-11-29 20:51:05 +05:30
include_context 'invalid urls'
it 'does not allow urls with CR or LF characters' do
project = build(:project)
aggregate_failures do
urls_with_CRLF.each do |url|
project.import_url = url
expect(project).not_to be_valid
expect(project.errors.full_messages.first).to match(/is blocked: URI is invalid/)
end
end
end
2018-11-08 19:23:39 +05:30
end
2017-08-17 22:00:37 +05:30
describe 'project pending deletion' do
let!(:project_pending_deletion) do
2017-09-10 17:25:29 +05:30
create(:project,
2017-08-17 22:00:37 +05:30
pending_delete: true)
end
2020-10-24 23:57:45 +05:30
2017-08-17 22:00:37 +05:30
let(:new_project) do
2017-09-10 17:25:29 +05:30
build(:project,
2017-08-17 22:00:37 +05:30
name: project_pending_deletion.name,
namespace: project_pending_deletion.namespace)
end
before do
new_project.validate
end
it 'contains errors related to the project being deleted' do
2020-01-01 13:55:28 +05:30
expect(new_project.errors.full_messages.first).to eq(_('The project is still being deleted. Please try again later.'))
2017-08-17 22:00:37 +05:30
end
end
describe 'path validation' do
it 'allows paths reserved on the root namespace' do
project = build(:project, path: 'api')
expect(project).to be_valid
end
it 'rejects paths reserved on another level' do
project = build(:project, path: 'tree')
expect(project).not_to be_valid
end
it 'rejects nested paths' do
parent = create(:group, :nested, path: 'environments')
project = build(:project, path: 'folders', namespace: parent)
expect(project).not_to be_valid
end
it 'allows a reserved group name' do
parent = create(:group)
project = build(:project, path: 'avatar', namespace: parent)
expect(project).to be_valid
end
2018-03-17 18:26:18 +05:30
it 'allows a path ending in a period' do
project = build(:project, path: 'foo.')
expect(project).to be_valid
end
2017-08-17 22:00:37 +05:30
end
2014-09-02 18:07:02 +05:30
end
2016-04-02 18:10:28 +05:30
2019-02-15 15:39:39 +05:30
describe '#all_pipelines' do
2019-02-02 18:00:53 +05:30
let(:project) { create(:project) }
before do
create(:ci_pipeline, project: project, ref: 'master', source: :web)
create(:ci_pipeline, project: project, ref: 'master', source: :external)
end
it 'has all pipelines' do
2019-02-15 15:39:39 +05:30
expect(project.all_pipelines.size).to eq(2)
2019-02-02 18:00:53 +05:30
end
context 'when builds are disabled' do
before do
project.project_feature.update_attribute(:builds_access_level, ProjectFeature::DISABLED)
end
2019-07-07 11:18:12 +05:30
it 'returns .external pipelines' do
2019-02-15 15:39:39 +05:30
expect(project.all_pipelines).to all(have_attributes(source: 'external'))
expect(project.all_pipelines.size).to eq(1)
2019-02-02 18:00:53 +05:30
end
end
end
2020-10-24 23:57:45 +05:30
describe '#has_packages?' do
let(:project) { create(:project, :public) }
subject { project.has_packages?(package_type) }
shared_examples 'returning true examples' do
let!(:package) { create("#{package_type}_package", project: project) }
it { is_expected.to be true }
end
shared_examples 'returning false examples' do
it { is_expected.to be false }
end
context 'with maven packages' do
it_behaves_like 'returning true examples' do
let(:package_type) { :maven }
end
end
context 'with npm packages' do
it_behaves_like 'returning true examples' do
let(:package_type) { :npm }
end
end
context 'with conan packages' do
it_behaves_like 'returning true examples' do
let(:package_type) { :conan }
end
end
context 'with no package type' do
it_behaves_like 'returning false examples' do
let(:package_type) { nil }
end
end
end
2019-07-07 11:18:12 +05:30
describe '#ci_pipelines' do
let(:project) { create(:project) }
before do
create(:ci_pipeline, project: project, ref: 'master', source: :web)
create(:ci_pipeline, project: project, ref: 'master', source: :external)
end
it 'has ci pipelines' do
expect(project.ci_pipelines.size).to eq(2)
end
context 'when builds are disabled' do
before do
project.project_feature.update_attribute(:builds_access_level, ProjectFeature::DISABLED)
end
it 'returns .external pipelines' do
expect(project.ci_pipelines).to all(have_attributes(source: 'external'))
expect(project.ci_pipelines.size).to eq(1)
end
end
end
2020-03-13 15:44:24 +05:30
describe '#autoclose_referenced_issues' do
context 'when DB entry is nil' do
let(:project) { create(:project, autoclose_referenced_issues: nil) }
it 'returns true' do
expect(project.autoclose_referenced_issues).to be_truthy
end
end
context 'when DB entry is true' do
let(:project) { create(:project, autoclose_referenced_issues: true) }
it 'returns true' do
expect(project.autoclose_referenced_issues).to be_truthy
end
end
context 'when DB entry is false' do
let(:project) { create(:project, autoclose_referenced_issues: false) }
it 'returns false' do
expect(project.autoclose_referenced_issues).to be_falsey
end
end
end
2015-12-23 02:04:40 +05:30
describe 'project token' do
2016-09-13 17:45:13 +05:30
it 'sets an random token if none provided' do
2018-11-08 19:23:39 +05:30
project = FactoryBot.create(:project, runners_token: '')
2015-12-23 02:04:40 +05:30
expect(project.runners_token).not_to eq('')
end
2016-09-29 09:46:39 +05:30
it 'does not set an random token if one provided' do
2018-11-08 19:23:39 +05:30
project = FactoryBot.create(:project, runners_token: 'my-token')
2015-12-23 02:04:40 +05:30
expect(project.runners_token).to eq('my-token')
end
end
2014-09-02 18:07:02 +05:30
2015-04-26 12:48:37 +05:30
describe 'Respond to' do
it { is_expected.to respond_to(:url_to_repo) }
it { is_expected.to respond_to(:execute_hooks) }
it { is_expected.to respond_to(:owner) }
it { is_expected.to respond_to(:path_with_namespace) }
2017-09-10 17:25:29 +05:30
it { is_expected.to respond_to(:full_path) }
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
describe 'delegation' do
2018-11-18 11:00:15 +05:30
[:add_guest, :add_reporter, :add_developer, :add_maintainer, :add_user, :add_users].each do |method|
2017-09-10 17:25:29 +05:30
it { is_expected.to delegate_method(method).to(:team) }
end
it { is_expected.to delegate_method(:members).to(:team).with_prefix(true) }
it { is_expected.to delegate_method(:name).to(:owner).with_prefix(true).with_arguments(allow_nil: true) }
2019-02-15 15:39:39 +05:30
it { is_expected.to delegate_method(:root_ancestor).to(:namespace).with_arguments(allow_nil: true) }
2019-07-07 11:18:12 +05:30
it { is_expected.to delegate_method(:last_pipeline).to(:commit).with_arguments(allow_nil: true) }
end
2020-03-13 15:44:24 +05:30
describe 'reference methods' do
let_it_be(:owner) { create(:user, name: 'Gitlab') }
let_it_be(:namespace) { create(:namespace, name: 'Sample namespace', path: 'sample-namespace', owner: owner) }
let_it_be(:project) { create(:project, name: 'Sample project', path: 'sample-project', namespace: namespace) }
let_it_be(:group) { create(:group, name: 'Group', path: 'sample-group') }
let_it_be(:another_project) { create(:project, namespace: namespace) }
let_it_be(:another_namespace_project) { create(:project, name: 'another-project') }
2018-11-20 20:47:30 +05:30
2020-03-13 15:44:24 +05:30
describe '#to_reference' do
it 'returns the path with reference_postfix' do
expect(project.to_reference).to eq("#{project.full_path}>")
end
2015-09-11 14:41:01 +05:30
2020-03-13 15:44:24 +05:30
it 'returns the path with reference_postfix when arg is self' do
expect(project.to_reference(project)).to eq("#{project.full_path}>")
2017-08-17 22:00:37 +05:30
end
2020-03-13 15:44:24 +05:30
it 'returns the full_path with reference_postfix when full' do
expect(project.to_reference(full: true)).to eq("#{project.full_path}>")
2017-08-17 22:00:37 +05:30
end
2020-03-13 15:44:24 +05:30
it 'returns the full_path with reference_postfix when cross-project' do
expect(project.to_reference(build_stubbed(:project))).to eq("#{project.full_path}>")
2017-08-17 22:00:37 +05:30
end
end
2020-03-13 15:44:24 +05:30
describe '#to_reference_base' do
context 'when nil argument' do
it 'returns nil' do
expect(project.to_reference_base).to be_nil
end
2017-08-17 22:00:37 +05:30
end
2020-03-13 15:44:24 +05:30
context 'when full is true' do
it 'returns complete path to the project', :aggregate_failures do
be_full_path = eq('sample-namespace/sample-project')
2017-08-17 22:00:37 +05:30
2020-03-13 15:44:24 +05:30
expect(project.to_reference_base(full: true)).to be_full_path
expect(project.to_reference_base(project, full: true)).to be_full_path
expect(project.to_reference_base(group, full: true)).to be_full_path
end
2017-08-17 22:00:37 +05:30
end
2020-03-13 15:44:24 +05:30
context 'when same project argument' do
it 'returns nil' do
expect(project.to_reference_base(project)).to be_nil
end
end
2017-08-17 22:00:37 +05:30
2020-03-13 15:44:24 +05:30
context 'when cross namespace project argument' do
it 'returns complete path to the project' do
expect(project.to_reference_base(another_namespace_project)).to eq 'sample-namespace/sample-project'
end
2017-08-17 22:00:37 +05:30
end
2020-03-13 15:44:24 +05:30
context 'when same namespace / cross-project argument' do
2017-08-17 22:00:37 +05:30
it 'returns path to the project' do
2020-03-13 15:44:24 +05:30
expect(project.to_reference_base(another_project)).to eq 'sample-project'
2017-08-17 22:00:37 +05:30
end
end
2020-03-13 15:44:24 +05:30
context 'when different namespace / cross-project argument with same owner' do
let(:another_namespace_same_owner) { create(:namespace, path: 'another-namespace', owner: owner) }
let(:another_project_same_owner) { create(:project, path: 'another-project', namespace: another_namespace_same_owner) }
2017-08-17 22:00:37 +05:30
it 'returns full path to the project' do
2020-03-13 15:44:24 +05:30
expect(project.to_reference_base(another_project_same_owner)).to eq 'sample-namespace/sample-project'
2017-08-17 22:00:37 +05:30
end
end
2020-03-13 15:44:24 +05:30
context 'when argument is a namespace' do
context 'with same project path' do
it 'returns path to the project' do
expect(project.to_reference_base(namespace)).to eq 'sample-project'
end
end
2017-08-17 22:00:37 +05:30
2020-03-13 15:44:24 +05:30
context 'with different project path' do
it 'returns full path to the project' do
expect(project.to_reference_base(group)).to eq 'sample-namespace/sample-project'
end
end
2017-08-17 22:00:37 +05:30
end
2020-10-24 23:57:45 +05:30
context 'when argument is a user' do
it 'returns full path to the project' do
expect(project.to_reference_base(owner)).to eq 'sample-namespace/sample-project'
end
end
2017-08-17 22:00:37 +05:30
end
2020-03-13 15:44:24 +05:30
describe '#to_human_reference' do
context 'when nil argument' do
it 'returns nil' do
expect(project.to_human_reference).to be_nil
end
2017-08-17 22:00:37 +05:30
end
2020-03-13 15:44:24 +05:30
context 'when same project argument' do
it 'returns nil' do
expect(project.to_human_reference(project)).to be_nil
end
2017-08-17 22:00:37 +05:30
end
2020-03-13 15:44:24 +05:30
context 'when cross namespace project argument' do
it 'returns complete name with namespace of the project' do
expect(project.to_human_reference(another_namespace_project)).to eq 'Gitlab / Sample project'
end
end
2017-08-17 22:00:37 +05:30
2020-03-13 15:44:24 +05:30
context 'when same namespace / cross-project argument' do
it 'returns name of the project' do
expect(project.to_human_reference(another_project)).to eq 'Sample project'
end
2017-08-17 22:00:37 +05:30
end
2015-09-11 14:41:01 +05:30
end
end
2018-03-17 18:26:18 +05:30
describe '#merge_method' do
using RSpec::Parameterized::TableSyntax
2016-08-24 12:49:21 +05:30
2018-03-17 18:26:18 +05:30
where(:ff, :rebase, :method) do
true | true | :ff
true | false | :ff
false | true | :rebase_merge
false | false | :merge
2016-08-24 12:49:21 +05:30
end
2018-03-17 18:26:18 +05:30
with_them do
let(:project) { build(:project, merge_requests_rebase_enabled: rebase, merge_requests_ff_only_enabled: ff) }
subject { project.merge_method }
it { is_expected.to eq(method) }
2016-08-24 12:49:21 +05:30
end
2018-03-17 18:26:18 +05:30
end
2016-09-13 17:45:13 +05:30
it 'returns valid url to repo' do
2017-09-10 17:25:29 +05:30
project = described_class.new(path: 'somewhere')
2015-04-26 12:48:37 +05:30
expect(project.url_to_repo).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + 'somewhere.git')
2014-09-02 18:07:02 +05:30
end
2018-11-08 19:23:39 +05:30
describe "#readme_url" do
context 'with a non-existing repository' do
2018-12-13 13:39:08 +05:30
let(:project) { create(:project) }
2018-11-08 19:23:39 +05:30
2018-12-13 13:39:08 +05:30
it 'returns nil' do
2018-11-08 19:23:39 +05:30
expect(project.readme_url).to be_nil
end
end
context 'with an existing repository' do
context 'when no README exists' do
2018-12-13 13:39:08 +05:30
let(:project) { create(:project, :empty_repo) }
2018-11-08 19:23:39 +05:30
2018-12-13 13:39:08 +05:30
it 'returns nil' do
2018-11-08 19:23:39 +05:30
expect(project.readme_url).to be_nil
end
end
context 'when a README exists' do
2018-12-13 13:39:08 +05:30
let(:project) { create(:project, :repository) }
2018-11-08 19:23:39 +05:30
it 'returns the README' do
2020-03-13 15:44:24 +05:30
expect(project.readme_url).to eq("#{project.web_url}/-/blob/master/README.md")
2018-11-08 19:23:39 +05:30
end
end
end
end
2018-03-17 18:26:18 +05:30
describe "#new_issuable_address" do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project, path: "somewhere") }
2016-09-13 17:45:13 +05:30
let(:user) { create(:user) }
context 'incoming email enabled' do
before do
stub_incoming_email_setting(enabled: true, address: "p+%{key}@gl.ab")
end
it 'returns the address to create a new issue' do
2019-02-15 15:39:39 +05:30
address = "p+#{project.full_path_slug}-#{project.project_id}-#{user.incoming_email_token}-issue@gl.ab"
2016-09-13 17:45:13 +05:30
2018-03-17 18:26:18 +05:30
expect(project.new_issuable_address(user, 'issue')).to eq(address)
end
it 'returns the address to create a new merge request' do
2019-02-15 15:39:39 +05:30
address = "p+#{project.full_path_slug}-#{project.project_id}-#{user.incoming_email_token}-merge-request@gl.ab"
2018-03-17 18:26:18 +05:30
expect(project.new_issuable_address(user, 'merge_request')).to eq(address)
2016-09-13 17:45:13 +05:30
end
2019-02-15 15:39:39 +05:30
it 'returns nil with invalid address type' do
expect(project.new_issuable_address(user, 'invalid_param')).to be_nil
end
2016-09-13 17:45:13 +05:30
end
context 'incoming email disabled' do
before do
stub_incoming_email_setting(enabled: false)
end
it 'returns nil' do
2018-03-17 18:26:18 +05:30
expect(project.new_issuable_address(user, 'issue')).to be_nil
end
it 'returns nil' do
expect(project.new_issuable_address(user, 'merge_request')).to be_nil
2016-09-13 17:45:13 +05:30
end
end
end
2015-04-26 12:48:37 +05:30
describe 'last_activity methods' do
2016-11-03 12:29:30 +05:30
let(:timestamp) { 2.hours.ago }
# last_activity_at gets set to created_at upon creation
2017-09-10 17:25:29 +05:30
let(:project) { create(:project, created_at: timestamp, updated_at: timestamp) }
2014-09-02 18:07:02 +05:30
2015-04-26 12:48:37 +05:30
describe 'last_activity' do
2016-09-13 17:45:13 +05:30
it 'alias last_activity to last_event' do
2017-09-10 17:25:29 +05:30
last_event = create(:event, :closed, project: project)
2016-09-29 09:46:39 +05:30
2015-04-26 12:48:37 +05:30
expect(project.last_activity).to eq(last_event)
2014-09-02 18:07:02 +05:30
end
end
describe 'last_activity_date' do
it 'returns the creation date of the project\'s last event if present' do
2020-06-23 00:09:42 +05:30
new_event = create(:event, :closed, project: project, created_at: Time.current)
2016-09-29 09:46:39 +05:30
2016-11-03 12:29:30 +05:30
project.reload
2016-09-29 09:46:39 +05:30
expect(project.last_activity_at.to_i).to eq(new_event.created_at.to_i)
2014-09-02 18:07:02 +05:30
end
it 'returns the project\'s last update date if it has no events' do
2015-04-26 12:48:37 +05:30
expect(project.last_activity_date).to eq(project.updated_at)
2014-09-02 18:07:02 +05:30
end
2018-03-27 19:54:05 +05:30
it 'returns the most recent timestamp' do
2018-11-18 11:00:15 +05:30
project.update(updated_at: nil,
last_activity_at: timestamp,
last_repository_updated_at: timestamp - 1.hour)
2018-03-27 19:54:05 +05:30
2018-11-08 19:23:39 +05:30
expect(project.last_activity_date).to be_like_time(timestamp)
2018-03-27 19:54:05 +05:30
2018-11-18 11:00:15 +05:30
project.update(updated_at: timestamp,
last_activity_at: timestamp - 1.hour,
last_repository_updated_at: nil)
2018-03-27 19:54:05 +05:30
2018-11-08 19:23:39 +05:30
expect(project.last_activity_date).to be_like_time(timestamp)
2018-03-27 19:54:05 +05:30
end
2014-09-02 18:07:02 +05:30
end
end
2015-09-11 14:41:01 +05:30
describe '#get_issue' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2015-12-23 02:04:40 +05:30
let!(:issue) { create(:issue, project: project) }
2017-01-15 13:20:01 +05:30
let(:user) { create(:user) }
before do
2018-03-17 18:26:18 +05:30
project.add_developer(user)
2017-01-15 13:20:01 +05:30
end
2015-09-11 14:41:01 +05:30
context 'with default issues tracker' do
it 'returns an issue' do
2017-01-15 13:20:01 +05:30
expect(project.get_issue(issue.iid, user)).to eq issue
2015-09-11 14:41:01 +05:30
end
2015-12-23 02:04:40 +05:30
it 'returns count of open issues' do
expect(project.open_issues_count).to eq(1)
end
2015-09-11 14:41:01 +05:30
it 'returns nil when no issue found' do
2020-04-22 19:07:51 +05:30
expect(project.get_issue(non_existing_record_id, user)).to be_nil
2017-01-15 13:20:01 +05:30
end
it "returns nil when user doesn't have access" do
user = create(:user)
expect(project.get_issue(issue.iid, user)).to eq nil
2015-09-11 14:41:01 +05:30
end
end
context 'with external issues tracker' do
2017-09-10 17:25:29 +05:30
let!(:internal_issue) { create(:issue, project: project) }
2020-03-13 15:44:24 +05:30
2015-09-11 14:41:01 +05:30
before do
2017-09-10 17:25:29 +05:30
allow(project).to receive(:external_issue_tracker).and_return(true)
2015-09-11 14:41:01 +05:30
end
2017-09-10 17:25:29 +05:30
context 'when internal issues are enabled' do
it 'returns interlan issue' do
issue = project.get_issue(internal_issue.iid, user)
expect(issue).to be_kind_of(Issue)
expect(issue.iid).to eq(internal_issue.iid)
expect(issue.project).to eq(project)
end
it 'returns an ExternalIssue when internal issue does not exists' do
issue = project.get_issue('FOO-1234', user)
expect(issue).to be_kind_of(ExternalIssue)
expect(issue.iid).to eq('FOO-1234')
expect(issue.project).to eq(project)
end
end
context 'when internal issues are disabled' do
before do
project.issues_enabled = false
project.save!
end
it 'returns always an External issues' do
issue = project.get_issue(internal_issue.iid, user)
expect(issue).to be_kind_of(ExternalIssue)
expect(issue.iid).to eq(internal_issue.iid.to_s)
expect(issue.project).to eq(project)
end
it 'returns an ExternalIssue when internal issue does not exists' do
issue = project.get_issue('FOO-1234', user)
expect(issue).to be_kind_of(ExternalIssue)
expect(issue.iid).to eq('FOO-1234')
expect(issue.project).to eq(project)
end
2015-09-11 14:41:01 +05:30
end
end
end
describe '#issue_exists?' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2015-09-11 14:41:01 +05:30
it 'is truthy when issue exists' do
expect(project).to receive(:get_issue).and_return(double)
expect(project.issue_exists?(1)).to be_truthy
end
it 'is falsey when issue does not exist' do
expect(project).to receive(:get_issue).and_return(nil)
expect(project.issue_exists?(1)).to be_falsey
end
end
2016-08-24 12:49:21 +05:30
describe '#to_param' do
2014-09-02 18:07:02 +05:30
context 'with namespace' do
before do
2018-11-08 19:23:39 +05:30
@group = create(:group, name: 'gitlab')
2017-09-10 17:25:29 +05:30
@project = create(:project, name: 'gitlabhq', namespace: @group)
2014-09-02 18:07:02 +05:30
end
2015-04-26 12:48:37 +05:30
it { expect(@project.to_param).to eq('gitlabhq') }
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
context 'with invalid path' do
it 'returns previous path to keep project suitable for use in URLs when persisted' do
2017-09-10 17:25:29 +05:30
project = create(:project, path: 'gitlab')
2016-09-13 17:45:13 +05:30
project.path = 'foo&bar'
expect(project).not_to be_valid
expect(project.to_param).to eq 'gitlab'
end
it 'returns current path when new record' do
2017-09-10 17:25:29 +05:30
project = build(:project, path: 'gitlab')
2016-09-13 17:45:13 +05:30
project.path = 'foo&bar'
expect(project).not_to be_valid
expect(project.to_param).to eq 'foo&bar'
end
end
2014-09-02 18:07:02 +05:30
end
2016-08-24 12:49:21 +05:30
describe '#default_issues_tracker?' do
2016-09-13 17:45:13 +05:30
it "is true if used internal tracker" do
2017-09-10 17:25:29 +05:30
project = build(:project)
2017-08-17 22:00:37 +05:30
2015-04-26 12:48:37 +05:30
expect(project.default_issues_tracker?).to be_truthy
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it "is false if used other tracker" do
2017-08-17 22:00:37 +05:30
# NOTE: The current nature of this factory requires persistence
project = create(:redmine_project)
expect(project.default_issues_tracker?).to be_falsey
2014-09-02 18:07:02 +05:30
end
end
2016-08-24 12:49:21 +05:30
describe '#external_issue_tracker' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2014-09-02 18:07:02 +05:30
let(:ext_project) { create(:redmine_project) }
context 'on existing projects with no value for has_external_issue_tracker' do
2018-03-17 18:26:18 +05:30
before do
project.update_column(:has_external_issue_tracker, nil)
ext_project.update_column(:has_external_issue_tracker, nil)
end
it 'updates the has_external_issue_tracker boolean' do
expect do
project.external_issue_tracker
end.to change { project.reload.has_external_issue_tracker }.to(false)
expect do
ext_project.external_issue_tracker
end.to change { ext_project.reload.has_external_issue_tracker }.to(true)
end
end
it 'returns nil and does not query services when there is no external issue tracker' do
expect(project).not_to receive(:services)
expect(project.external_issue_tracker).to eq(nil)
end
it 'retrieves external_issue_tracker querying services and cache it when there is external issue tracker' do
ext_project.reload # Factory returns a project with changed attributes
expect(ext_project).to receive(:services).once.and_call_original
2.times { expect(ext_project.external_issue_tracker).to be_a_kind_of(RedmineService) }
2014-09-02 18:07:02 +05:30
end
end
2016-08-24 12:49:21 +05:30
describe '#cache_has_external_issue_tracker' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project, has_external_issue_tracker: nil) }
it 'stores true if there is any external_issue_tracker' do
services = double(:service, external_issue_trackers: [RedmineService.new])
expect(project).to receive(:services).and_return(services)
2014-09-02 18:07:02 +05:30
expect do
project.cache_has_external_issue_tracker
end.to change { project.has_external_issue_tracker}.to(true)
2014-09-02 18:07:02 +05:30
end
it 'stores false if there is no external_issue_tracker' do
services = double(:service, external_issue_trackers: [])
expect(project).to receive(:services).and_return(services)
2014-09-02 18:07:02 +05:30
expect do
project.cache_has_external_issue_tracker
end.to change { project.has_external_issue_tracker}.to(false)
2014-09-02 18:07:02 +05:30
end
2018-03-17 18:26:18 +05:30
it 'does not cache data when in a read-only GitLab instance' do
allow(Gitlab::Database).to receive(:read_only?) { true }
expect do
project.cache_has_external_issue_tracker
end.not_to change { project.has_external_issue_tracker }
end
end
describe '#cache_has_external_wiki' do
let(:project) { create(:project, has_external_wiki: nil) }
it 'stores true if there is any external_wikis' do
services = double(:service, external_wikis: [ExternalWikiService.new])
expect(project).to receive(:services).and_return(services)
expect do
project.cache_has_external_wiki
end.to change { project.has_external_wiki}.to(true)
end
it 'stores false if there is no external_wikis' do
services = double(:service, external_wikis: [])
expect(project).to receive(:services).and_return(services)
expect do
project.cache_has_external_wiki
end.to change { project.has_external_wiki}.to(false)
end
it 'does not cache data when in a read-only GitLab instance' do
allow(Gitlab::Database).to receive(:read_only?) { true }
expect do
project.cache_has_external_wiki
end.not_to change { project.has_external_wiki }
end
2014-09-02 18:07:02 +05:30
end
2016-09-29 09:46:39 +05:30
describe '#has_wiki?' do
2017-09-10 17:25:29 +05:30
let(:no_wiki_project) { create(:project, :wiki_disabled, has_external_wiki: false) }
let(:wiki_enabled_project) { create(:project) }
let(:external_wiki_project) { create(:project, has_external_wiki: true) }
2016-09-29 09:46:39 +05:30
it 'returns true if project is wiki enabled or has external wiki' do
expect(wiki_enabled_project).to have_wiki
expect(external_wiki_project).to have_wiki
expect(no_wiki_project).not_to have_wiki
end
end
2020-10-24 23:57:45 +05:30
describe '#default_owner' do
let_it_be(:owner) { create(:user) }
let_it_be(:namespace) { create(:namespace, owner: owner) }
context 'the project does not have a group' do
let(:project) { build(:project, namespace: namespace) }
it 'is the namespace owner' do
expect(project.default_owner).to eq(owner)
end
end
context 'the project is in a group' do
let(:group) { build(:group) }
let(:project) { build(:project, group: group, namespace: namespace) }
it 'is the group owner' do
allow(group).to receive(:default_owner).and_return(Object.new)
expect(project.default_owner).to eq(group.default_owner)
end
end
end
2016-08-24 12:49:21 +05:30
describe '#external_wiki' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2016-08-24 12:49:21 +05:30
context 'with an active external wiki' do
before do
create(:service, project: project, type: 'ExternalWikiService', active: true)
project.external_wiki
end
it 'sets :has_external_wiki as true' do
expect(project.has_external_wiki).to be(true)
end
it 'sets :has_external_wiki as false if an external wiki service is destroyed later' do
expect(project.has_external_wiki).to be(true)
project.services.external_wikis.first.destroy
expect(project.has_external_wiki).to be(false)
end
end
context 'with an inactive external wiki' do
before do
create(:service, project: project, type: 'ExternalWikiService', active: false)
end
it 'sets :has_external_wiki as false' do
expect(project.has_external_wiki).to be(false)
end
end
context 'with no external wiki' do
before do
project.external_wiki
end
it 'sets :has_external_wiki as false' do
expect(project.has_external_wiki).to be(false)
end
it 'sets :has_external_wiki as true if an external wiki service is created later' do
expect(project.has_external_wiki).to be(false)
create(:service, project: project, type: 'ExternalWikiService', active: true)
expect(project.has_external_wiki).to be(true)
end
end
end
2014-09-02 18:07:02 +05:30
describe '#star_count' do
it 'counts stars from multiple users' do
2018-11-08 19:23:39 +05:30
user1 = create(:user)
user2 = create(:user)
2017-09-10 17:25:29 +05:30
project = create(:project, :public)
2014-09-02 18:07:02 +05:30
expect(project.star_count).to eq(0)
user1.toggle_star(project)
expect(project.reload.star_count).to eq(1)
user2.toggle_star(project)
project.reload
expect(project.reload.star_count).to eq(2)
user1.toggle_star(project)
project.reload
expect(project.reload.star_count).to eq(1)
user2.toggle_star(project)
project.reload
expect(project.reload.star_count).to eq(0)
end
it 'counts stars on the right project' do
2018-11-08 19:23:39 +05:30
user = create(:user)
2017-09-10 17:25:29 +05:30
project1 = create(:project, :public)
project2 = create(:project, :public)
2014-09-02 18:07:02 +05:30
expect(project1.star_count).to eq(0)
expect(project2.star_count).to eq(0)
user.toggle_star(project1)
project1.reload
project2.reload
expect(project1.star_count).to eq(1)
expect(project2.star_count).to eq(0)
user.toggle_star(project1)
project1.reload
project2.reload
expect(project1.star_count).to eq(0)
expect(project2.star_count).to eq(0)
user.toggle_star(project2)
project1.reload
project2.reload
expect(project1.star_count).to eq(0)
expect(project2.star_count).to eq(1)
user.toggle_star(project2)
project1.reload
project2.reload
expect(project1.star_count).to eq(0)
expect(project2.star_count).to eq(0)
end
end
2015-04-26 12:48:37 +05:30
2016-08-24 12:49:21 +05:30
describe '#avatar_type' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2015-04-26 12:48:37 +05:30
2016-09-13 17:45:13 +05:30
it 'is true if avatar is image' do
2015-04-26 12:48:37 +05:30
project.update_attribute(:avatar, 'uploads/avatar.png')
expect(project.avatar_type).to be_truthy
end
2016-09-13 17:45:13 +05:30
it 'is false if avatar is html page' do
2015-04-26 12:48:37 +05:30
project.update_attribute(:avatar, 'uploads/avatar.html')
2018-11-08 19:23:39 +05:30
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'])
2015-04-26 12:48:37 +05:30
end
end
2016-08-24 12:49:21 +05:30
describe '#avatar_url' do
2015-04-26 12:48:37 +05:30
subject { project.avatar_url }
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2015-04-26 12:48:37 +05:30
2017-08-17 22:00:37 +05:30
context 'when avatar file is uploaded' do
2018-03-17 18:26:18 +05:30
let(:project) { create(:project, :public, :with_avatar) }
2015-04-26 12:48:37 +05:30
2017-09-10 17:25:29 +05:30
it 'shows correct url' do
2018-03-17 18:26:18 +05:30
expect(project.avatar_url).to eq(project.avatar.url)
expect(project.avatar_url(only_path: false)).to eq([Gitlab.config.gitlab.url, project.avatar.url].join)
2017-09-10 17:25:29 +05:30
end
2015-04-26 12:48:37 +05:30
end
2018-03-17 18:26:18 +05:30
context 'when avatar file in git' do
2015-04-26 12:48:37 +05:30
before do
allow(project).to receive(:avatar_in_git) { true }
end
2019-09-04 21:01:54 +05:30
let(:avatar_path) { "/#{project.full_path}/-/avatar" }
2015-04-26 12:48:37 +05:30
2017-09-10 17:25:29 +05:30
it { is_expected.to eq "http://#{Gitlab.config.gitlab.host}#{avatar_path}" }
2015-04-26 12:48:37 +05:30
end
2016-06-02 11:05:42 +05:30
context 'when git repo is empty' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2016-06-02 11:05:42 +05:30
2017-09-10 17:25:29 +05:30
it { is_expected.to eq nil }
2016-06-02 11:05:42 +05:30
end
2015-04-26 12:48:37 +05:30
end
2015-10-24 18:46:33 +05:30
2016-09-29 09:46:39 +05:30
describe '#pipeline_for' do
2017-08-17 22:00:37 +05:30
let(:project) { create(:project, :repository) }
2015-10-24 18:46:33 +05:30
2016-09-29 09:46:39 +05:30
shared_examples 'giving the correct pipeline' do
it { is_expected.to eq(pipeline) }
2016-06-02 11:05:42 +05:30
2016-09-29 09:46:39 +05:30
context 'return latest' do
2019-03-02 22:35:43 +05:30
let!(:pipeline2) { create_pipeline(project) }
2016-06-02 11:05:42 +05:30
2016-09-29 09:46:39 +05:30
it { is_expected.to eq(pipeline2) }
2016-06-02 11:05:42 +05:30
end
2016-09-29 09:46:39 +05:30
end
2019-10-12 21:52:04 +05:30
context 'with a matching pipeline' do
let!(:pipeline) { create_pipeline(project) }
context 'with explicit sha' do
subject { project.pipeline_for('master', pipeline.sha) }
2016-09-29 09:46:39 +05:30
2019-10-12 21:52:04 +05:30
it_behaves_like 'giving the correct pipeline'
context 'with supplied id' do
let!(:other_pipeline) { create_pipeline(project) }
subject { project.pipeline_for('master', pipeline.sha, other_pipeline.id) }
it { is_expected.to eq(other_pipeline) }
end
end
context 'with implicit sha' do
subject { project.pipeline_for('master') }
it_behaves_like 'giving the correct pipeline'
end
2016-09-29 09:46:39 +05:30
end
2019-10-12 21:52:04 +05:30
context 'when there is no matching pipeline' do
2016-09-29 09:46:39 +05:30
subject { project.pipeline_for('master') }
2016-06-02 11:05:42 +05:30
2019-10-12 21:52:04 +05:30
it { is_expected.to be_nil }
2016-09-29 09:46:39 +05:30
end
2015-10-24 18:46:33 +05:30
end
2019-10-12 21:52:04 +05:30
describe '#pipelines_for' do
let(:project) { create(:project, :repository) }
let!(:pipeline) { create_pipeline(project) }
let!(:other_pipeline) { create_pipeline(project) }
subject { project.pipelines_for(project.default_branch, project.commit.sha) }
it { is_expected.to contain_exactly(pipeline, other_pipeline) }
end
2016-08-24 12:49:21 +05:30
describe '#builds_enabled' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2015-10-24 18:46:33 +05:30
2015-11-26 14:37:03 +05:30
subject { project.builds_enabled }
it { expect(project.builds_enabled?).to be_truthy }
2015-10-24 18:46:33 +05:30
end
2018-12-05 23:21:45 +05:30
describe '.sort_by_attribute' do
it 'reorders the input relation by start count desc' do
project1 = create(:project, star_count: 2)
project2 = create(:project, star_count: 1)
project3 = create(:project)
projects = described_class.sort_by_attribute(:stars_desc)
expect(projects).to eq([project1, project2, project3])
end
end
2017-08-17 22:00:37 +05:30
describe '.with_shared_runners' do
2017-09-10 17:25:29 +05:30
subject { described_class.with_shared_runners }
2017-08-17 22:00:37 +05:30
context 'when shared runners are enabled for project' do
2017-09-10 17:25:29 +05:30
let!(:project) { create(:project, shared_runners_enabled: true) }
2017-08-17 22:00:37 +05:30
it "returns a project" do
is_expected.to eq([project])
end
end
context 'when shared runners are disabled for project' do
2017-09-10 17:25:29 +05:30
let!(:project) { create(:project, shared_runners_enabled: false) }
2017-08-17 22:00:37 +05:30
it "returns an empty array" do
is_expected.to be_empty
end
end
end
2017-09-10 17:25:29 +05:30
describe '.cached_count', :use_clean_rails_memory_store_caching do
2016-08-24 12:49:21 +05:30
let(:group) { create(:group, :public) }
2017-09-10 17:25:29 +05:30
let!(:project1) { create(:project, :public, group: group) }
let!(:project2) { create(:project, :public, group: group) }
2016-08-24 12:49:21 +05:30
it 'returns total project count' do
2017-09-10 17:25:29 +05:30
expect(described_class).to receive(:count).once.and_call_original
2016-08-24 12:49:21 +05:30
3.times do
2017-09-10 17:25:29 +05:30
expect(described_class.cached_count).to eq(2)
2016-08-24 12:49:21 +05:30
end
end
end
2015-10-24 18:46:33 +05:30
describe '.trending' do
2016-06-02 11:05:42 +05:30
let(:group) { create(:group, :public) }
2020-03-13 15:44:24 +05:30
let(:project1) { create(:project, :public, :repository, group: group) }
let(:project2) { create(:project, :public, :repository, group: group) }
2015-10-24 18:46:33 +05:30
before do
2020-03-13 15:44:24 +05:30
create_list(:note_on_commit, 2, project: project1)
2015-10-24 18:46:33 +05:30
create(:note_on_commit, project: project2)
2016-11-03 12:29:30 +05:30
TrendingProject.refresh!
2015-10-24 18:46:33 +05:30
end
2016-11-03 12:29:30 +05:30
subject { described_class.trending.to_a }
2015-10-24 18:46:33 +05:30
2016-11-03 12:29:30 +05:30
it 'sorts projects by the amount of notes in descending order' do
expect(subject).to eq([project1, project2])
end
2015-10-24 18:46:33 +05:30
2016-11-03 12:29:30 +05:30
it 'does not take system notes into account' do
2020-03-13 15:44:24 +05:30
create_list(:note_on_commit, 10, project: project2, system: true)
2015-10-24 18:46:33 +05:30
2016-11-03 12:29:30 +05:30
expect(described_class.trending.to_a).to eq([project1, project2])
2015-10-24 18:46:33 +05:30
end
end
2015-11-26 14:37:03 +05:30
2017-09-10 17:25:29 +05:30
describe '.starred_by' do
it 'returns only projects starred by the given user' do
user1 = create(:user)
user2 = create(:user)
project1 = create(:project)
project2 = create(:project)
create(:project)
user1.toggle_star(project1)
user2.toggle_star(project2)
expect(described_class.starred_by(user1)).to contain_exactly(project1)
end
end
2020-01-01 13:55:28 +05:30
describe '.with_limit' do
it 'limits the number of projects returned' do
create_list(:project, 3)
expect(described_class.with_limit(1).count).to eq(1)
end
end
2015-11-26 14:37:03 +05:30
describe '.visible_to_user' do
2017-09-10 17:25:29 +05:30
let!(:project) { create(:project, :private) }
2015-11-26 14:37:03 +05:30
let!(:user) { create(:user) }
subject { described_class.visible_to_user(user) }
describe 'when a user has access to a project' do
before do
2018-11-18 11:00:15 +05:30
project.add_user(user, Gitlab::Access::MAINTAINER)
2015-11-26 14:37:03 +05:30
end
it { is_expected.to eq([project]) }
end
describe 'when a user does not have access to any projects' do
it { is_expected.to eq([]) }
end
end
2015-12-23 02:04:40 +05:30
2020-01-01 13:55:28 +05:30
describe '.with_service' do
before do
create_list(:prometheus_project, 2)
end
it 'avoid n + 1' do
expect { described_class.with_service(:prometheus_service).map(&:prometheus_service) }.not_to exceed_query_limit(1)
end
end
2020-07-28 23:09:34 +05:30
describe '.service_desk_enabled' do
it 'returns the correct project' do
project_with_service_desk_enabled = create(:project)
project_with_service_desk_disabled = create(:project, :service_desk_disabled)
expect(described_class.service_desk_enabled).to include(project_with_service_desk_enabled)
expect(described_class.service_desk_enabled).not_to include(project_with_service_desk_disabled)
end
end
describe '#service_desk_enabled?' do
let_it_be(:namespace) { create(:namespace) }
subject(:project) { build(:project, :private, namespace: namespace, service_desk_enabled: true) }
before do
allow(Gitlab::IncomingEmail).to receive(:enabled?).and_return(true)
allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?).and_return(true)
end
it 'is enabled' do
expect(project.service_desk_enabled?).to be_truthy
expect(project.service_desk_enabled).to be_truthy
end
end
describe '#service_desk_address' do
2020-10-24 23:57:45 +05:30
let_it_be(:project, reload: true) { create(:project, service_desk_enabled: true) }
2020-07-28 23:09:34 +05:30
2020-10-24 23:57:45 +05:30
subject { project.service_desk_address }
shared_examples 'with incoming email address' do
context 'when incoming email is enabled' do
before do
config = double(enabled: true, address: 'test+%{key}@mail.com')
allow(::Gitlab.config).to receive(:incoming_email).and_return(config)
end
it 'uses project full path as service desk address key' do
expect(project.service_desk_address).to eq("test+#{project.full_path_slug}-#{project.project_id}-issue-@mail.com")
end
end
context 'when incoming email is disabled' do
before do
config = double(enabled: false)
allow(::Gitlab.config).to receive(:incoming_email).and_return(config)
end
it 'uses project full path as service desk address key' do
expect(project.service_desk_address).to be_nil
end
end
end
context 'when service_desk_email is disabled' do
before do
allow(::Gitlab::ServiceDeskEmail).to receive(:enabled?).and_return(false)
end
it_behaves_like 'with incoming email address'
2020-07-28 23:09:34 +05:30
end
2020-10-24 23:57:45 +05:30
context 'when service_desk_email is enabled' do
before do
config = double(enabled: true, address: 'foo+%{key}@bar.com')
allow(::Gitlab::ServiceDeskEmail).to receive(:config).and_return(config)
end
context 'when service_desk_custom_address flag is enabled' do
before do
stub_feature_flags(service_desk_custom_address: true)
end
it 'returns custom address when project_key is set' do
create(:service_desk_setting, project: project, project_key: 'key1')
expect(subject).to eq("foo+#{project.full_path_slug}-key1@bar.com")
end
it_behaves_like 'with incoming email address'
end
context 'when service_desk_custom_address flag is disabled' do
before do
stub_feature_flags(service_desk_custom_address: false)
end
it_behaves_like 'with incoming email address'
end
2020-07-28 23:09:34 +05:30
end
end
describe '.find_by_service_desk_project_key' do
it 'returns the correct project' do
project1 = create(:project)
project2 = create(:project)
create(:service_desk_setting, project: project1, project_key: 'key1')
create(:service_desk_setting, project: project2, project_key: 'key2')
expect(Project.find_by_service_desk_project_key('key1')).to eq(project1)
expect(Project.find_by_service_desk_project_key('key2')).to eq(project2)
end
it 'returns nil if there is no project with the key' do
expect(Project.find_by_service_desk_project_key('some_key')).to be_nil
end
end
2016-08-24 12:49:21 +05:30
context 'repository storage by default' do
2018-10-15 14:42:47 +05:30
let(:project) { build(:project) }
2016-08-24 12:49:21 +05:30
2016-11-24 13:41:30 +05:30
it 'picks storage from ApplicationSetting' do
2020-04-22 19:07:51 +05:30
expect_next_instance_of(ApplicationSetting) do |instance|
expect(instance).to receive(:pick_repository_storage).and_return('picked')
end
expect(described_class).to receive(:pick_repository_storage).and_call_original
2016-11-24 13:41:30 +05:30
expect(project.repository_storage).to eq('picked')
end
2016-08-24 12:49:21 +05:30
end
2015-12-23 02:04:40 +05:30
context 'shared runners by default' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2015-12-23 02:04:40 +05:30
subject { project.shared_runners_enabled }
context 'are enabled' do
2017-09-10 17:25:29 +05:30
before do
stub_application_setting(shared_runners_enabled: true)
end
2015-12-23 02:04:40 +05:30
it { is_expected.to be_truthy }
end
context 'are disabled' do
2017-09-10 17:25:29 +05:30
before do
stub_application_setting(shared_runners_enabled: false)
end
2015-12-23 02:04:40 +05:30
it { is_expected.to be_falsey }
end
end
2018-10-15 14:42:47 +05:30
describe '#any_runners?' do
context 'shared runners' do
2018-11-08 19:23:39 +05:30
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) }
2015-12-23 02:04:40 +05:30
2018-10-15 14:42:47 +05:30
context 'for shared runners disabled' do
let(:shared_runners_enabled) { false }
2016-04-02 18:10:28 +05:30
2018-10-15 14:42:47 +05:30
it 'has no runners available' do
expect(project.any_runners?).to be_falsey
end
2016-04-02 18:10:28 +05:30
2018-10-15 14:42:47 +05:30
it 'has a specific runner' do
2018-11-08 19:23:39 +05:30
specific_runner
2018-10-15 14:42:47 +05:30
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
end
it 'checks the presence of specific runner' do
2018-11-08 19:23:39 +05:30
specific_runner
2018-10-15 14:42:47 +05:30
expect(project.any_runners? { |runner| runner == specific_runner }).to be_truthy
end
2016-04-02 18:10:28 +05:30
2018-10-15 14:42:47 +05:30
it 'returns false if match cannot be found' do
2018-11-08 19:23:39 +05:30
specific_runner
2018-10-15 14:42:47 +05:30
expect(project.any_runners? { false }).to be_falsey
end
2015-12-23 02:04:40 +05:30
end
2016-04-02 18:10:28 +05:30
2018-10-15 14:42:47 +05:30
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
2015-12-23 02:04:40 +05:30
end
end
2016-04-02 18:10:28 +05:30
2018-10-15 14:42:47 +05:30
context 'group runners' do
2018-11-08 19:23:39 +05:30
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]) }
2018-10-15 14:42:47 +05:30
context 'for group runners disabled' do
let(:group_runners_enabled) { false }
2016-04-02 18:10:28 +05:30
2018-10-15 14:42:47 +05:30
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
2015-12-23 02:04:40 +05:30
end
2018-10-15 14:42:47 +05:30
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
2015-12-23 02:04:40 +05:30
end
end
end
2017-08-17 22:00:37 +05:30
describe '#shared_runners' do
2018-11-08 19:23:39 +05:30
let!(:runner) { create(:ci_runner, :instance) }
2017-08-17 22:00:37 +05:30
subject { project.shared_runners }
context 'when shared runners are enabled for project' do
2017-09-10 17:25:29 +05:30
let!(:project) { create(:project, shared_runners_enabled: true) }
2017-08-17 22:00:37 +05:30
it "returns a list of shared runners" do
is_expected.to eq([runner])
end
end
context 'when shared runners are disabled for project' do
2017-09-10 17:25:29 +05:30
let!(:project) { create(:project, shared_runners_enabled: false) }
2017-08-17 22:00:37 +05:30
it "returns a empty list" do
is_expected.to be_empty
end
end
end
2019-03-02 22:35:43 +05:30
describe '#visibility_level' do
let(:project) { build(:project) }
subject { project.visibility_level }
context 'by default' do
it { is_expected.to eq(Gitlab::VisibilityLevel::PRIVATE) }
end
context 'when set to INTERNAL in application settings' do
2019-09-04 21:01:54 +05:30
using RSpec::Parameterized::TableSyntax
2019-03-02 22:35:43 +05:30
before do
stub_application_setting(default_project_visibility: Gitlab::VisibilityLevel::INTERNAL)
end
it { is_expected.to eq(Gitlab::VisibilityLevel::INTERNAL) }
2019-09-04 21:01:54 +05:30
where(:attribute_name, :value) do
:visibility | 'public'
:visibility_level | Gitlab::VisibilityLevel::PUBLIC
'visibility' | 'public'
'visibility_level' | Gitlab::VisibilityLevel::PUBLIC
end
with_them do
it 'sets the visibility level' do
proj = described_class.new(attribute_name => value, name: 'test', path: 'test')
expect(proj.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
end
end
2019-03-02 22:35:43 +05:30
end
end
describe '#visibility_level_allowed?' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project, :internal) }
context 'when checking on non-forked project' do
it { expect(project.visibility_level_allowed?(Gitlab::VisibilityLevel::PRIVATE)).to be_truthy }
it { expect(project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_truthy }
it { expect(project.visibility_level_allowed?(Gitlab::VisibilityLevel::PUBLIC)).to be_truthy }
end
context 'when checking on forked project' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project, :internal) }
2018-12-13 13:39:08 +05:30
let(:forked_project) { fork_project(project) }
it { expect(forked_project.visibility_level_allowed?(Gitlab::VisibilityLevel::PRIVATE)).to be_truthy }
it { expect(forked_project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_truthy }
it { expect(forked_project.visibility_level_allowed?(Gitlab::VisibilityLevel::PUBLIC)).to be_falsey }
end
2016-06-02 11:05:42 +05:30
end
2017-08-17 22:00:37 +05:30
describe '#pages_deployed?' do
2018-11-08 19:23:39 +05:30
let(:project) { create(:project) }
2017-08-17 22:00:37 +05:30
subject { project.pages_deployed? }
2020-10-24 23:57:45 +05:30
context 'if pages are deployed' do
2017-09-10 17:25:29 +05:30
before do
2020-10-24 23:57:45 +05:30
project.pages_metadatum.update_column(:deployed, true)
2017-09-10 17:25:29 +05:30
end
2017-08-17 22:00:37 +05:30
it { is_expected.to be_truthy }
end
context "if public folder doesn't exist" do
it { is_expected.to be_falsey }
end
end
2020-04-08 14:13:33 +05:30
describe '#default_branch_protected?' do
using RSpec::Parameterized::TableSyntax
let_it_be(:project) { create(:project) }
subject { project.default_branch_protected? }
where(:default_branch_protection_level, :result) do
Gitlab::Access::PROTECTION_NONE | false
Gitlab::Access::PROTECTION_DEV_CAN_PUSH | false
Gitlab::Access::PROTECTION_DEV_CAN_MERGE | true
Gitlab::Access::PROTECTION_FULL | true
end
with_them do
before do
expect(project.namespace).to receive(:default_branch_protection).and_return(default_branch_protection_level)
end
it { is_expected.to eq(result) }
end
end
2017-09-10 17:25:29 +05:30
describe '#pages_url' do
2018-11-08 19:23:39 +05:30
let(:group) { create(:group, name: group_name) }
let(:project) { create(:project, namespace: group, name: project_name) }
2017-09-10 17:25:29 +05:30
let(:domain) { 'Example.com' }
subject { project.pages_url }
before do
allow(Settings.pages).to receive(:host).and_return(domain)
allow(Gitlab.config.pages).to receive(:url).and_return('http://example.com')
end
context 'group page' do
let(:group_name) { 'Group' }
let(:project_name) { 'group.example.com' }
it { is_expected.to eq("http://group.example.com") }
2020-07-28 23:09:34 +05:30
context 'mixed case path' do
before do
project.update!(path: 'Group.example.com')
end
it { is_expected.to eq("http://group.example.com") }
end
2017-09-10 17:25:29 +05:30
end
context 'project page' do
let(:group_name) { 'Group' }
let(:project_name) { 'Project' }
it { is_expected.to eq("http://group.example.com/project") }
2020-07-28 23:09:34 +05:30
context 'mixed case path' do
before do
project.update!(path: 'Project')
end
it { is_expected.to eq("http://group.example.com/Project") }
end
2017-09-10 17:25:29 +05:30
end
end
2018-05-09 12:01:36 +05:30
describe '#pages_group_url' do
2018-11-08 19:23:39 +05:30
let(:group) { create(:group, name: group_name) }
let(:project) { create(:project, namespace: group, name: project_name) }
2018-05-09 12:01:36 +05:30
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
2016-06-02 11:05:42 +05:30
describe '.search' do
2020-01-01 13:55:28 +05:30
let_it_be(:project) { create(:project, description: 'kitten mittens') }
2016-06-02 11:05:42 +05:30
it 'returns projects with a matching name' do
expect(described_class.search(project.name)).to eq([project])
end
it 'returns projects with a partially matching name' do
expect(described_class.search(project.name[0..2])).to eq([project])
end
it 'returns projects with a matching name regardless of the casing' do
expect(described_class.search(project.name.upcase)).to eq([project])
end
it 'returns projects with a matching description' do
expect(described_class.search(project.description)).to eq([project])
end
it 'returns projects with a partially matching description' do
expect(described_class.search('kitten')).to eq([project])
end
it 'returns projects with a matching description regardless of the casing' do
expect(described_class.search('KITTEN')).to eq([project])
end
it 'returns projects with a matching path' do
expect(described_class.search(project.path)).to eq([project])
end
2016-06-02 11:05:42 +05:30
it 'returns projects with a partially matching path' do
expect(described_class.search(project.path[0..2])).to eq([project])
end
it 'returns projects with a matching path regardless of the casing' do
expect(described_class.search(project.path.upcase)).to eq([project])
end
2020-04-22 19:07:51 +05:30
context 'when include_namespace is true' do
2020-01-01 13:55:28 +05:30
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
2020-04-22 19:07:51 +05:30
it 'returns projects that match the group path' do
expect(described_class.search(group.path, include_namespace: true)).to eq([project])
2020-01-01 13:55:28 +05:30
end
2020-04-22 19:07:51 +05:30
it 'returns projects that match the full path' do
expect(described_class.search(project.full_path, include_namespace: true)).to eq([project])
2020-01-01 13:55:28 +05:30
end
end
2017-09-10 17:25:29 +05:30
describe 'with pending_delete project' do
let(:pending_delete_project) { create(:project, pending_delete: true) }
it 'shows pending deletion project' do
search_result = described_class.search(pending_delete_project.name)
expect(search_result).to eq([pending_delete_project])
end
end
end
2016-04-02 18:10:28 +05:30
2018-11-20 20:47:30 +05:30
describe '.optionally_search' do
let(:project) { create(:project) }
it 'searches for projects matching the query if one is given' do
relation = described_class.optionally_search(project.name)
expect(relation).to eq([project])
end
it 'returns the current relation if no search query is given' do
relation = described_class.where(id: project.id)
expect(relation.optionally_search).to eq(relation)
end
end
2020-01-01 13:55:28 +05:30
describe '.eager_load_namespace_and_owner' do
2018-11-20 20:47:30 +05:30
it 'eager loads the namespace and namespace owner' do
create(:project)
2020-01-01 13:55:28 +05:30
row = described_class.eager_load_namespace_and_owner.first
2018-11-20 20:47:30 +05:30
recorder = ActiveRecord::QueryRecorder.new { row.namespace.owner }
expect(recorder.count).to be_zero
end
end
2016-04-02 18:10:28 +05:30
describe '#expire_caches_before_rename' do
2017-08-17 22:00:37 +05:30
let(:project) { create(:project, :repository) }
2016-04-02 18:10:28 +05:30
let(:repo) { double(:repo, exists?: true) }
let(:wiki) { double(:wiki, exists?: true) }
2020-05-24 23:13:21 +05:30
let(:design) { double(:design, exists?: true) }
2016-04-02 18:10:28 +05:30
it 'expires the caches of the repository and wiki' do
2020-04-08 14:13:33 +05:30
# In EE, there are design repositories as well
allow(Repository).to receive(:new).and_call_original
2017-09-10 17:25:29 +05:30
allow(Repository).to receive(:new)
2020-04-08 14:13:33 +05:30
.with('foo', project, shard: project.repository_storage)
2017-09-10 17:25:29 +05:30
.and_return(repo)
2016-04-02 18:10:28 +05:30
2017-09-10 17:25:29 +05:30
allow(Repository).to receive(:new)
2020-04-08 14:13:33 +05:30
.with('foo.wiki', project, shard: project.repository_storage, repo_type: Gitlab::GlRepository::WIKI)
2017-09-10 17:25:29 +05:30
.and_return(wiki)
2016-04-02 18:10:28 +05:30
2020-05-24 23:13:21 +05:30
allow(Repository).to receive(:new)
.with('foo.design', project, shard: project.repository_storage, repo_type: Gitlab::GlRepository::DESIGN)
.and_return(design)
2016-06-02 11:05:42 +05:30
expect(repo).to receive(:before_delete)
expect(wiki).to receive(:before_delete)
2020-05-24 23:13:21 +05:30
expect(design).to receive(:before_delete)
2016-04-02 18:10:28 +05:30
project.expire_caches_before_rename('foo')
end
end
2016-06-02 11:05:42 +05:30
describe '.search_by_title' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project, name: 'kittens') }
2016-06-02 11:05:42 +05:30
it 'returns projects with a matching name' do
expect(described_class.search_by_title(project.name)).to eq([project])
end
it 'returns projects with a partially matching name' do
expect(described_class.search_by_title('kitten')).to eq([project])
end
it 'returns projects with a matching name regardless of the casing' do
expect(described_class.search_by_title('KITTENS')).to eq([project])
end
end
context 'when checking projects from groups' do
let(:private_group) { create(:group, visibility_level: 0) }
let(:internal_group) { create(:group, visibility_level: 10) }
2018-11-08 19:23:39 +05:30
let(:private_project) { create(:project, :private, group: private_group) }
let(:internal_project) { create(:project, :internal, group: internal_group) }
2016-06-02 11:05:42 +05:30
context 'when group is private project can not be internal' do
it { expect(private_project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_falsey }
end
context 'when group is internal project can not be public' do
it { expect(internal_project.visibility_level_allowed?(Gitlab::VisibilityLevel::PUBLIC)).to be_falsey }
end
end
2019-02-15 15:39:39 +05:30
describe '#track_project_repository' do
shared_examples 'tracks storage location' do
context 'when a project repository entry does not exist' do
it 'creates a new entry' do
expect { project.track_project_repository }.to change(project, :project_repository)
end
it 'tracks the project storage location' do
project.track_project_repository
expect(project.project_repository).to have_attributes(
disk_path: project.disk_path,
shard_name: project.repository_storage
)
end
end
context 'when a tracking entry exists' do
let!(:project_repository) { create(:project_repository, project: project) }
let!(:shard) { create(:shard, name: 'foo') }
it 'does not create a new entry in the database' do
expect { project.track_project_repository }.not_to change(project, :project_repository)
end
it 'updates the project storage location' do
allow(project).to receive(:disk_path).and_return('fancy/new/path')
allow(project).to receive(:repository_storage).and_return('foo')
project.track_project_repository
expect(project.project_repository).to have_attributes(
disk_path: 'fancy/new/path',
shard_name: 'foo'
)
end
end
end
context 'with projects on legacy storage' do
let(:project) { create(:project, :repository, :legacy_storage) }
it_behaves_like 'tracks storage location'
end
context 'with projects on hashed storage' do
let(:project) { create(:project, :repository) }
it_behaves_like 'tracks storage location'
end
end
2016-06-02 11:05:42 +05:30
describe '#create_repository' do
2017-08-17 22:00:37 +05:30
let(:project) { create(:project, :repository) }
2016-06-02 11:05:42 +05:30
context 'using a regular repository' do
it 'creates the repository' do
2020-04-08 14:13:33 +05:30
expect(project.repository).to receive(:create_repository)
2016-06-02 11:05:42 +05:30
expect(project.create_repository).to eq(true)
end
it 'adds an error if the repository could not be created' do
2020-04-08 14:13:33 +05:30
expect(project.repository).to receive(:create_repository) { raise 'Fail in test' }
2016-06-02 11:05:42 +05:30
expect(project.create_repository).to eq(false)
expect(project.errors).not_to be_empty
end
end
context 'using a forked repository' do
it 'does nothing' do
expect(project).to receive(:forked?).and_return(true)
2020-04-08 14:13:33 +05:30
expect(project.repository).not_to receive(:create_repository)
2016-06-02 11:05:42 +05:30
project.create_repository
end
end
end
2017-09-10 17:25:29 +05:30
describe '#ensure_repository' do
let(:project) { create(:project, :repository) }
it 'creates the repository if it not exist' do
2020-04-08 14:13:33 +05:30
allow(project).to receive(:repository_exists?).and_return(false)
2017-09-10 17:25:29 +05:30
expect(project).to receive(:create_repository).with(force: true)
project.ensure_repository
end
it 'does not create the repository if it exists' do
2020-04-08 14:13:33 +05:30
allow(project).to receive(:repository_exists?).and_return(true)
2017-09-10 17:25:29 +05:30
expect(project).not_to receive(:create_repository)
project.ensure_repository
end
it 'creates the repository if it is a fork' do
expect(project).to receive(:forked?).and_return(true)
2020-04-08 14:13:33 +05:30
expect(project).to receive(:repository_exists?).and_return(false)
expect(project.repository).to receive(:create_repository) { true }
2017-09-10 17:25:29 +05:30
project.ensure_repository
end
end
2019-02-15 15:39:39 +05:30
describe 'handling import URL' do
it 'returns the sanitized URL' do
project = create(:project, :import_started, import_url: 'http://user:pass@test.com')
project.import_state.finish
expect(project.reload.import_url).to eq('http://test.com')
end
2020-03-13 15:44:24 +05:30
it 'saves the url credentials percent decoded' do
url = 'http://user:pass%21%3F%40@github.com/t.git'
project = build(:project, import_url: url)
# When the credentials are not decoded this expectation fails
expect(project.import_url).to eq(url)
expect(project.import_data.credentials).to eq(user: 'user', password: 'pass!?@')
end
it 'saves url with no credentials' do
url = 'http://github.com/t.git'
project = build(:project, import_url: url)
expect(project.import_url).to eq(url)
expect(project.import_data.credentials).to eq(user: nil, password: nil)
end
2019-02-15 15:39:39 +05:30
end
2017-08-17 22:00:37 +05:30
describe '#container_registry_url' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2016-06-02 11:05:42 +05:30
2017-08-17 22:00:37 +05:30
subject { project.container_registry_url }
2016-06-02 11:05:42 +05:30
2017-09-10 17:25:29 +05:30
before do
stub_container_registry_config(**registry_settings)
end
2016-06-02 11:05:42 +05:30
context 'for enabled registry' do
let(:registry_settings) do
2017-08-17 22:00:37 +05:30
{ enabled: true,
host_port: 'example.com' }
2016-06-02 11:05:42 +05:30
end
it { is_expected.not_to be_nil }
2016-06-02 11:05:42 +05:30
end
context 'for disabled registry' do
let(:registry_settings) do
2017-08-17 22:00:37 +05:30
{ enabled: false }
2016-06-02 11:05:42 +05:30
end
it { is_expected.to be_nil }
end
end
describe '#has_container_registry_tags?' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2016-06-02 11:05:42 +05:30
2017-08-17 22:00:37 +05:30
context 'when container registry is enabled' do
2017-09-10 17:25:29 +05:30
before do
stub_container_registry_config(enabled: true)
end
2016-06-02 11:05:42 +05:30
2017-08-17 22:00:37 +05:30
context 'when tags are present for multi-level registries' do
before do
create(:container_repository, project: project, name: 'image')
stub_container_registry_tags(repository: /image/,
tags: %w[latest rc1])
end
2019-07-07 11:18:12 +05:30
it 'has image tags' do
2017-08-17 22:00:37 +05:30
expect(project).to have_container_registry_tags
end
end
context 'when tags are present for root repository' do
before do
stub_container_registry_tags(repository: project.full_path,
tags: %w[latest rc1 pre1])
end
2016-06-02 11:05:42 +05:30
2019-07-07 11:18:12 +05:30
it 'has image tags' do
2017-08-17 22:00:37 +05:30
expect(project).to have_container_registry_tags
end
2016-06-02 11:05:42 +05:30
end
2017-08-17 22:00:37 +05:30
context 'when there are no tags at all' do
before do
stub_container_registry_tags(repository: :any, tags: [])
end
2016-06-02 11:05:42 +05:30
2019-07-07 11:18:12 +05:30
it 'does not have image tags' do
2017-08-17 22:00:37 +05:30
expect(project).not_to have_container_registry_tags
end
2016-06-02 11:05:42 +05:30
end
end
2017-08-17 22:00:37 +05:30
context 'when container registry is disabled' do
2017-09-10 17:25:29 +05:30
before do
stub_container_registry_config(enabled: false)
end
2016-06-02 11:05:42 +05:30
2019-07-07 11:18:12 +05:30
it 'does not have image tags' do
2017-08-17 22:00:37 +05:30
expect(project).not_to have_container_registry_tags
end
2019-07-07 11:18:12 +05:30
it 'does not check root repository tags' do
2017-08-17 22:00:37 +05:30
expect(project).not_to receive(:full_path)
expect(project).not_to have_container_registry_tags
end
2019-07-07 11:18:12 +05:30
it 'iterates through container repositories' do
2017-08-17 22:00:37 +05:30
expect(project).to receive(:container_repositories)
expect(project).not_to have_container_registry_tags
end
2016-06-02 11:05:42 +05:30
end
end
2017-09-10 17:25:29 +05:30
describe '#ci_config_path=' do
2019-12-26 22:10:19 +05:30
using RSpec::Parameterized::TableSyntax
2017-09-10 17:25:29 +05:30
2019-12-26 22:10:19 +05:30
let(:project) { create(:project) }
2017-09-10 17:25:29 +05:30
2019-12-26 22:10:19 +05:30
where(:default_ci_config_path, :project_ci_config_path, :expected_ci_config_path) do
nil | :notset | :default
nil | nil | :default
nil | '' | :default
nil | "cust\0om/\0/path" | 'custom//path'
'' | :notset | :default
'' | nil | :default
'' | '' | :default
'' | "cust\0om/\0/path" | 'custom//path'
'global/path' | :notset | 'global/path'
'global/path' | nil | :default
'global/path' | '' | :default
'global/path' | "cust\0om/\0/path" | 'custom//path'
2017-09-10 17:25:29 +05:30
end
2019-12-26 22:10:19 +05:30
with_them do
before do
stub_application_setting(default_ci_config_path: default_ci_config_path)
2017-09-10 17:25:29 +05:30
2019-12-26 22:10:19 +05:30
if project_ci_config_path != :notset
project.ci_config_path = project_ci_config_path
end
end
2017-09-10 17:25:29 +05:30
2019-12-26 22:10:19 +05:30
it 'returns the correct path' do
expect(project.ci_config_path.presence || :default).to eq(expected_ci_config_path)
end
2017-09-10 17:25:29 +05:30
end
end
2020-03-13 15:44:24 +05:30
describe '#uses_default_ci_config?' do
let(:project) { build(:project)}
it 'has a custom ci config path' do
project.ci_config_path = 'something_custom'
expect(project.uses_default_ci_config?).to be_falsey
end
it 'has a blank ci config path' do
project.ci_config_path = ''
expect(project.uses_default_ci_config?).to be_truthy
end
it 'does not have a custom ci config path' do
project.ci_config_path = nil
expect(project.uses_default_ci_config?).to be_truthy
end
end
2019-10-12 21:52:04 +05:30
describe '#latest_successful_build_for_ref' do
2017-08-17 22:00:37 +05:30
let(:project) { create(:project, :repository) }
2019-03-02 22:35:43 +05:30
let(:pipeline) { create_pipeline(project) }
2016-08-24 12:49:21 +05:30
2019-10-12 21:52:04 +05:30
it_behaves_like 'latest successful build for sha or ref'
2016-08-24 12:49:21 +05:30
2019-10-12 21:52:04 +05:30
subject { project.latest_successful_build_for_ref(build_name) }
2016-08-24 12:49:21 +05:30
2019-10-12 21:52:04 +05:30
context 'with a specified ref' do
let(:build) { create_build }
2016-08-24 12:49:21 +05:30
2019-10-12 21:52:04 +05:30
subject { project.latest_successful_build_for_ref(build.name, project.default_branch) }
2016-08-24 12:49:21 +05:30
2019-10-12 21:52:04 +05:30
it { is_expected.to eq(build) }
2019-03-02 22:35:43 +05:30
end
2019-10-12 21:52:04 +05:30
end
2019-03-02 22:35:43 +05:30
2019-12-04 20:38:33 +05:30
describe '#latest_pipeline_for_ref' do
let(:project) { create(:project, :repository) }
let(:second_branch) { project.repository.branches[2] }
let!(:pipeline_for_default_branch) do
create(:ci_empty_pipeline, project: project, sha: project.commit.id,
ref: project.default_branch)
end
2020-10-24 23:57:45 +05:30
2019-12-04 20:38:33 +05:30
let!(:pipeline_for_second_branch) do
create(:ci_empty_pipeline, project: project, sha: second_branch.target,
ref: second_branch.name)
end
before do
create(:ci_empty_pipeline, project: project, sha: project.commit.parent.id,
ref: project.default_branch)
end
context 'default repository branch' do
subject { project.latest_pipeline_for_ref(project.default_branch) }
it { is_expected.to eq(pipeline_for_default_branch) }
end
context 'provided ref' do
subject { project.latest_pipeline_for_ref(second_branch.name) }
it { is_expected.to eq(pipeline_for_second_branch) }
end
context 'bad ref' do
subject { project.latest_pipeline_for_ref(SecureRandom.uuid) }
it { is_expected.to be_nil }
end
end
2019-10-12 21:52:04 +05:30
describe '#latest_successful_build_for_sha' do
let(:project) { create(:project, :repository) }
let(:pipeline) { create_pipeline(project) }
2019-03-02 22:35:43 +05:30
2019-10-12 21:52:04 +05:30
it_behaves_like 'latest successful build for sha or ref'
subject { project.latest_successful_build_for_sha(build_name, project.commit.sha) }
2019-03-02 22:35:43 +05:30
end
2019-10-12 21:52:04 +05:30
describe '#latest_successful_build_for_ref!' do
2019-03-02 22:35:43 +05:30
let(:project) { create(:project, :repository) }
let(:pipeline) { create_pipeline(project) }
context 'with many builds' do
it 'gives the latest builds from latest pipeline' do
pipeline1 = create_pipeline(project)
pipeline2 = create_pipeline(project)
create_build(pipeline1, 'test')
create_build(pipeline1, 'test2')
build1_p2 = create_build(pipeline2, 'test')
create_build(pipeline2, 'test2')
2019-10-12 21:52:04 +05:30
expect(project.latest_successful_build_for_ref!(build1_p2.name))
2019-03-02 22:35:43 +05:30
.to eq(build1_p2)
end
end
context 'with succeeded pipeline' do
let!(:build) { create_build }
context 'standalone pipeline' do
it 'returns builds for ref for default_branch' do
2019-10-12 21:52:04 +05:30
expect(project.latest_successful_build_for_ref!(build.name))
2019-03-02 22:35:43 +05:30
.to eq(build)
2016-08-24 12:49:21 +05:30
end
2019-02-15 15:39:39 +05:30
2019-03-02 22:35:43 +05:30
it 'returns exception if the build cannot be found' do
2019-10-12 21:52:04 +05:30
expect { project.latest_successful_build_for_ref!(build.name, 'TAIL') }
2019-03-02 22:35:43 +05:30
.to raise_error(ActiveRecord::RecordNotFound)
2019-02-15 15:39:39 +05:30
end
2016-08-24 12:49:21 +05:30
end
context 'with some pending pipeline' do
before do
2019-03-02 22:35:43 +05:30
create_build(create_pipeline(project, 'pending'))
2016-08-24 12:49:21 +05:30
end
it 'gives the latest build from latest pipeline' do
2019-10-12 21:52:04 +05:30
expect(project.latest_successful_build_for_ref!(build.name))
2019-03-02 22:35:43 +05:30
.to eq(build)
2016-08-24 12:49:21 +05:30
end
end
end
context 'with pending pipeline' do
it 'returns empty relation' do
2019-03-02 22:35:43 +05:30
pipeline.update(status: 'pending')
pending_build = create_build(pipeline)
2016-08-24 12:49:21 +05:30
2019-10-12 21:52:04 +05:30
expect { project.latest_successful_build_for_ref!(pending_build.name) }
2019-03-02 22:35:43 +05:30
.to raise_error(ActiveRecord::RecordNotFound)
2016-08-24 12:49:21 +05:30
end
end
end
2019-02-15 15:39:39 +05:30
describe '#import_status' do
context 'with import_state' do
it 'returns the right status' do
project = create(:project, :import_started)
expect(project.import_status).to eq("started")
end
end
context 'without import_state' do
it 'returns none' do
project = create(:project)
expect(project.import_status).to eq('none')
end
end
end
2020-04-22 19:07:51 +05:30
describe '#jira_import_status' do
let(:project) { create(:project, import_type: 'jira') }
context 'when no jira imports' do
it 'returns none' do
expect(project.jira_import_status).to eq('initial')
end
end
context 'when there are jira imports' do
let(:jira_import1) { build(:jira_import_state, :finished, project: project) }
let(:jira_import2) { build(:jira_import_state, project: project) }
before do
expect(project).to receive(:latest_jira_import).and_return(jira_import2)
end
context 'when latest import status is initial or jira imports are mising' do
it 'returns initial' do
expect(project.jira_import_status).to eq('initial')
end
end
context 'when latest import status is scheduled' do
before do
jira_import2.schedule!
end
it 'returns scheduled' do
expect(project.jira_import_status).to eq('scheduled')
end
end
end
end
2019-02-15 15:39:39 +05:30
describe '#human_import_status_name' do
context 'with import_state' do
it 'returns the right human import status' do
project = create(:project, :import_started)
2020-01-01 13:55:28 +05:30
expect(project.human_import_status_name).to eq(_('started'))
2019-02-15 15:39:39 +05:30
end
end
context 'without import_state' do
it 'returns none' do
project = create(:project)
expect(project.human_import_status_name).to eq('none')
end
end
end
2016-08-24 12:49:21 +05:30
describe '#add_import_job' do
2018-03-17 18:26:18 +05:30
let(:import_jid) { '123' }
2016-08-24 12:49:21 +05:30
context 'forked' do
2018-12-13 13:39:08 +05:30
let(:forked_from_project) { create(:project, :repository) }
let(:project) { create(:project) }
before do
fork_project(forked_from_project, nil, target_project: project)
end
2016-08-24 12:49:21 +05:30
it 'schedules a RepositoryForkWorker job' do
2018-05-09 12:01:36 +05:30
expect(RepositoryForkWorker).to receive(:perform_async).with(project.id).and_return(import_jid)
2016-08-24 12:49:21 +05:30
2018-03-17 18:26:18 +05:30
expect(project.add_import_job).to eq(import_jid)
2016-08-24 12:49:21 +05:30
end
2019-07-07 11:18:12 +05:30
context 'without repository' do
it 'schedules RepositoryImportWorker' do
project = create(:project, import_url: generate(:url))
expect(RepositoryImportWorker).to receive(:perform_async).with(project.id).and_return(import_jid)
expect(project.add_import_job).to eq(import_jid)
end
end
2016-08-24 12:49:21 +05:30
end
context 'not forked' do
it 'schedules a RepositoryImportWorker job' do
2017-09-10 17:25:29 +05:30
project = create(:project, import_url: generate(:url))
2018-03-17 18:26:18 +05:30
expect(RepositoryImportWorker).to receive(:perform_async).with(project.id).and_return(import_jid)
expect(project.add_import_job).to eq(import_jid)
2016-08-24 12:49:21 +05:30
end
end
2020-04-22 19:07:51 +05:30
context 'jira import' do
it 'schedules a jira import job' do
project = create(:project, import_type: 'jira')
jira_import = create(:jira_import_state, project: project)
expect(Gitlab::JiraImport::Stage::StartImportWorker).to receive(:perform_async).with(project.id).and_return(import_jid)
jira_import.schedule!
expect(jira_import.jid).to eq(import_jid)
end
end
end
describe '#jira_import?' do
let_it_be(:project) { build(:project, import_type: 'jira') }
let_it_be(:jira_import) { build(:jira_import_state, project: project) }
before do
expect(project).to receive(:jira_imports).and_return([jira_import])
end
it { expect(project.jira_import?).to be true }
it { expect(project.import?).to be true }
end
describe '#remove_import_data' do
let_it_be(:import_data) { ProjectImportData.new(data: { 'test' => 'some data' }) }
context 'when jira import' do
let_it_be(:project, reload: true) { create(:project, import_type: 'jira', import_data: import_data) }
let_it_be(:jira_import) { create(:jira_import_state, project: project) }
it 'does remove import data' do
expect(project.mirror?).to be false
expect(project.jira_import?).to be true
expect { project.remove_import_data }.to change { ProjectImportData.count }.by(-1)
end
end
context 'when neither a mirror nor a jira import' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, import_type: 'github', import_data: import_data) }
it 'removes import data' do
expect(project.mirror?).to be false
expect(project.jira_import?).to be false
expect { project.remove_import_data }.to change { ProjectImportData.count }.by(-1)
end
end
2016-08-24 12:49:21 +05:30
end
2017-08-17 22:00:37 +05:30
describe '#gitlab_project_import?' do
2017-09-10 17:25:29 +05:30
subject(:project) { build(:project, import_type: 'gitlab_project') }
2017-08-17 22:00:37 +05:30
it { expect(project.gitlab_project_import?).to be true }
end
describe '#gitea_import?' do
2017-09-10 17:25:29 +05:30
subject(:project) { build(:project, import_type: 'gitea') }
2017-08-17 22:00:37 +05:30
it { expect(project.gitea_import?).to be true }
end
2018-10-15 14:42:47 +05:30
describe '#has_remote_mirror?' do
let(:project) { create(:project, :remote_mirror, :import_started) }
2020-03-13 15:44:24 +05:30
2018-10-15 14:42:47 +05:30
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
2018-11-18 11:00:15 +05:30
project.remote_mirrors.first.update(enabled: false)
2018-10-15 14:42:47 +05:30
is_expected.to be_falsy
end
end
describe '#update_remote_mirrors' do
let(:project) { create(:project, :remote_mirror, :import_started) }
2020-03-13 15:44:24 +05:30
2018-10-15 14:42:47 +05:30
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
2018-11-18 11:00:15 +05:30
project.remote_mirrors.first.update(enabled: false)
2018-10-15 14:42:47 +05:30
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
2019-10-12 21:52:04 +05:30
describe '#mark_stuck_remote_mirrors_as_failed!' do
it 'fails stuck remote mirrors' do
project = create(:project, :repository, :remote_mirror)
project.remote_mirrors.first.update(
update_status: :started,
last_update_started_at: 2.days.ago
)
expect do
project.mark_stuck_remote_mirrors_as_failed!
end.to change { project.remote_mirrors.stuck.count }.from(1).to(0)
end
end
describe '#ancestors_upto' do
2018-03-17 18:26:18 +05:30
let(:parent) { create(:group) }
let(:child) { create(:group, parent: parent) }
let(:child2) { create(:group, parent: child) }
let(:project) { create(:project, namespace: child2) }
it 'returns all ancestors when no namespace is given' do
expect(project.ancestors_upto).to contain_exactly(child2, child, parent)
end
it 'includes ancestors upto but excluding the given ancestor' do
expect(project.ancestors_upto(parent)).to contain_exactly(child2, child)
end
2019-02-15 15:39:39 +05:30
describe 'with hierarchy_order' do
it 'returns ancestors ordered by descending hierarchy' do
expect(project.ancestors_upto(hierarchy_order: :desc)).to eq([parent, child, child2])
end
it 'can be used with upto option' do
expect(project.ancestors_upto(parent, hierarchy_order: :desc)).to eq([child, child2])
end
end
end
describe '#root_ancestor' do
let(:project) { create(:project) }
subject { project.root_ancestor }
it { is_expected.to eq(project.namespace) }
context 'in a group' do
let(:group) { create(:group) }
let(:project) { create(:project, group: group) }
it { is_expected.to eq(group) }
end
2019-10-12 21:52:04 +05:30
context 'in a nested group' do
2019-02-15 15:39:39 +05:30
let(:root) { create(:group) }
let(:child) { create(:group, parent: root) }
let(:project) { create(:project, group: child) }
it { is_expected.to eq(root) }
end
2018-03-17 18:26:18 +05:30
end
2019-10-12 21:52:04 +05:30
describe '#emails_disabled?' do
let(:project) { create(:project, emails_disabled: false) }
context 'emails disabled in group' do
it 'returns true' do
allow(project.namespace).to receive(:emails_disabled?) { true }
expect(project.emails_disabled?).to be_truthy
end
end
context 'emails enabled in group' do
before do
allow(project.namespace).to receive(:emails_disabled?) { false }
end
it 'returns false' do
expect(project.emails_disabled?).to be_falsey
end
it 'returns true' do
project.update_attribute(:emails_disabled, true)
expect(project.emails_disabled?).to be_truthy
end
end
end
2016-09-29 09:46:39 +05:30
describe '#lfs_enabled?' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2016-09-29 09:46:39 +05:30
shared_examples 'project overrides group' do
it 'returns true when enabled in project' do
project.update_attribute(:lfs_enabled, true)
expect(project.lfs_enabled?).to be_truthy
end
it 'returns false when disabled in project' do
project.update_attribute(:lfs_enabled, false)
expect(project.lfs_enabled?).to be_falsey
end
it 'returns the value from the namespace, when no value is set in project' do
expect(project.lfs_enabled?).to eq(project.namespace.lfs_enabled?)
end
end
context 'LFS disabled in group' do
before do
project.namespace.update_attribute(:lfs_enabled, false)
enable_lfs
end
it_behaves_like 'project overrides group'
end
context 'LFS enabled in group' do
before do
project.namespace.update_attribute(:lfs_enabled, true)
enable_lfs
end
it_behaves_like 'project overrides group'
end
describe 'LFS disabled globally' do
shared_examples 'it always returns false' do
it do
expect(project.lfs_enabled?).to be_falsey
expect(project.namespace.lfs_enabled?).to be_falsey
end
end
context 'when no values are set' do
it_behaves_like 'it always returns false'
end
context 'when all values are set to true' do
before do
project.namespace.update_attribute(:lfs_enabled, true)
project.update_attribute(:lfs_enabled, true)
end
it_behaves_like 'it always returns false'
end
end
end
2017-08-17 22:00:37 +05:30
describe '#change_head' do
let(:project) { create(:project, :repository) }
2016-08-24 12:49:21 +05:30
2018-03-17 18:26:18 +05:30
it 'returns error if branch does not exist' do
expect(project.change_head('unexisted-branch')).to be false
expect(project.errors.size).to eq(1)
end
2017-08-17 22:00:37 +05:30
it 'calls the before_change_head and after_change_head methods' do
2016-09-29 09:46:39 +05:30
expect(project.repository).to receive(:before_change_head)
2017-08-17 22:00:37 +05:30
expect(project.repository).to receive(:after_change_head)
2016-09-29 09:46:39 +05:30
project.change_head(project.default_branch)
end
2019-07-07 11:18:12 +05:30
it 'updates commit count' do
expect(ProjectCacheWorker).to receive(:perform_async).with(project.id, [], [:commit_count])
project.change_head(project.default_branch)
end
2016-09-29 09:46:39 +05:30
it 'copies the gitattributes' do
expect(project.repository).to receive(:copy_gitattributes).with(project.default_branch)
project.change_head(project.default_branch)
end
it 'reloads the default branch' do
expect(project).to receive(:reload_default_branch)
project.change_head(project.default_branch)
end
end
2018-03-17 18:26:18 +05:30
context 'forks' do
include ProjectForksHelper
let(:project) { create(:project, :public) }
let!(:forked_project) { fork_project(project) }
describe '#fork_network' do
it 'includes a fork of the project' do
expect(project.fork_network.projects).to include(forked_project)
end
it 'includes a fork of a fork' do
other_fork = fork_project(forked_project)
expect(project.fork_network.projects).to include(other_fork)
end
it 'includes sibling forks' do
other_fork = fork_project(project)
expect(forked_project.fork_network.projects).to include(other_fork)
end
it 'includes the base project' do
expect(forked_project.fork_network.projects).to include(project.reload)
end
end
describe '#in_fork_network_of?' do
it 'is true for a real fork' do
expect(forked_project.in_fork_network_of?(project)).to be_truthy
end
2019-10-12 21:52:04 +05:30
it 'is true for a fork of a fork' do
2018-03-17 18:26:18 +05:30
other_fork = fork_project(forked_project)
expect(other_fork.in_fork_network_of?(project)).to be_truthy
end
it 'is true for sibling forks' do
sibling = fork_project(project)
expect(sibling.in_fork_network_of?(forked_project)).to be_truthy
end
it 'is false when another project is given' do
other_project = build_stubbed(:project)
expect(forked_project.in_fork_network_of?(other_project)).to be_falsy
end
end
describe '#fork_source' do
let!(:second_fork) { fork_project(forked_project) }
it 'returns the direct source if it exists' do
expect(second_fork.fork_source).to eq(forked_project)
end
it 'returns the root of the fork network when the directs source was deleted' do
forked_project.destroy
expect(second_fork.fork_source).to eq(project)
end
it 'returns nil if it is the root of the fork network' do
expect(project.fork_source).to be_nil
end
end
2018-12-13 13:39:08 +05:30
describe '#forks' do
it 'includes direct forks of the project' do
expect(project.forks).to contain_exactly(forked_project)
end
end
2018-03-17 18:26:18 +05:30
describe '#lfs_storage_project' do
it 'returns self for non-forks' do
expect(project.lfs_storage_project).to eq project
end
it 'returns the fork network root for forks' do
second_fork = fork_project(forked_project)
expect(second_fork.lfs_storage_project).to eq project
end
it 'returns self when fork_source is nil' do
expect(forked_project).to receive(:fork_source).and_return(nil)
expect(forked_project.lfs_storage_project).to eq forked_project
end
end
2018-05-09 12:01:36 +05:30
describe '#all_lfs_objects' do
let(:lfs_object) { create(:lfs_object) }
2020-03-13 15:44:24 +05:30
context 'when LFS object is only associated to the source' do
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
2018-05-09 12:01:36 +05:30
end
2020-03-13 15:44:24 +05:30
context 'when LFS object is only associated to the fork' do
before do
forked_project.lfs_objects << lfs_object
end
it 'returns nothing' do
expect(project.all_lfs_objects).to be_empty
end
it 'returns the lfs object for a fork' do
expect(forked_project.all_lfs_objects).to contain_exactly(lfs_object)
end
2018-05-09 12:01:36 +05:30
end
2020-03-13 15:44:24 +05:30
context 'when LFS object is associated to both source and fork' do
before do
project.lfs_objects << lfs_object
forked_project.lfs_objects << lfs_object
end
it 'returns the lfs object for the source and fork' do
expect(project.all_lfs_objects).to contain_exactly(lfs_object)
expect(forked_project.all_lfs_objects).to contain_exactly(lfs_object)
end
2018-05-09 12:01:36 +05:30
end
end
2018-03-17 18:26:18 +05:30
end
2019-02-15 15:39:39 +05:30
describe '#set_repository_read_only!' do
let(:project) { create(:project) }
it 'returns true when there is no existing git transfer in progress' do
expect(project.set_repository_read_only!).to be_truthy
end
it 'returns false when there is an existing git transfer in progress' do
allow(project).to receive(:git_transfer_in_progress?) { true }
expect(project.set_repository_read_only!).to be_falsey
end
end
2019-03-13 22:55:13 +05:30
describe '#set_repository_writable!' do
it 'sets repository_read_only to false' do
project = create(:project, :read_only)
expect { project.set_repository_writable! }
.to change(project, :repository_read_only)
.from(true).to(false)
end
end
2016-09-29 09:46:39 +05:30
describe '#pushes_since_gc' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2016-09-29 09:46:39 +05:30
after do
project.reset_pushes_since_gc
end
context 'without any pushes' do
it 'returns 0' do
expect(project.pushes_since_gc).to eq(0)
end
end
context 'with a number of pushes' do
it 'returns the number of pushes' do
3.times { project.increment_pushes_since_gc }
expect(project.pushes_since_gc).to eq(3)
end
end
end
describe '#increment_pushes_since_gc' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2016-09-29 09:46:39 +05:30
after do
project.reset_pushes_since_gc
end
it 'increments the number of pushes since the last GC' do
3.times { project.increment_pushes_since_gc }
expect(project.pushes_since_gc).to eq(3)
end
end
describe '#reset_pushes_since_gc' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2016-09-29 09:46:39 +05:30
after do
project.reset_pushes_since_gc
end
it 'resets the number of pushes since the last GC' do
3.times { project.increment_pushes_since_gc }
project.reset_pushes_since_gc
expect(project.pushes_since_gc).to eq(0)
end
end
2017-08-17 22:00:37 +05:30
describe '#deployment_variables' do
2019-10-12 21:52:04 +05:30
let(:project) { create(:project) }
let(:environment) { 'production' }
2020-01-01 13:55:28 +05:30
let(:namespace) { 'namespace' }
2016-09-29 09:46:39 +05:30
2020-01-01 13:55:28 +05:30
subject { project.deployment_variables(environment: environment, kubernetes_namespace: namespace) }
2019-10-12 21:52:04 +05:30
2020-07-28 23:09:34 +05:30
context 'when the deployment platform is stubbed' do
before do
expect(project).to receive(:deployment_platform).with(environment: environment)
.and_return(deployment_platform)
end
context 'when project has a deployment platform' do
let(:platform_variables) { %w(platform variables) }
let(:deployment_platform) { double }
before do
expect(deployment_platform).to receive(:predefined_variables)
.with(project: project, environment_name: environment, kubernetes_namespace: namespace)
.and_return(platform_variables)
end
it { is_expected.to eq platform_variables }
end
2017-08-17 22:00:37 +05:30
2020-07-28 23:09:34 +05:30
context 'when project has no deployment platform' do
let(:deployment_platform) { nil }
2019-07-07 11:18:12 +05:30
2020-07-28 23:09:34 +05:30
it { is_expected.to eq [] }
end
2019-07-07 11:18:12 +05:30
end
2020-07-28 23:09:34 +05:30
context 'when project has a deployment platforms' do
let(:project) { create(:project) }
let!(:default_cluster) do
create(:cluster,
:not_managed,
platform_type: :kubernetes,
projects: [project],
environment_scope: '*',
platform_kubernetes: default_cluster_kubernetes)
end
2019-09-04 21:01:54 +05:30
2020-07-28 23:09:34 +05:30
let!(:review_env_cluster) do
create(:cluster,
:not_managed,
platform_type: :kubernetes,
projects: [project],
environment_scope: 'review/*',
platform_kubernetes: review_env_cluster_kubernetes)
2018-03-17 18:26:18 +05:30
end
2020-07-28 23:09:34 +05:30
let(:default_cluster_kubernetes) { create(:cluster_platform_kubernetes, token: 'default-AAA') }
let(:review_env_cluster_kubernetes) { create(:cluster_platform_kubernetes, token: 'review-AAA') }
context 'when environment name is review/name' do
let!(:environment) { create(:environment, project: project, name: 'review/name') }
it 'returns variables from this service' do
expect(project.deployment_variables(environment: 'review/name'))
.to include(key: 'KUBE_TOKEN', value: 'review-AAA', public: false, masked: true)
end
end
context 'when environment name is other' do
let!(:environment) { create(:environment, project: project, name: 'staging/name') }
it 'returns variables from this service' do
expect(project.deployment_variables(environment: 'staging/name'))
.to include(key: 'KUBE_TOKEN', value: 'default-AAA', public: false, masked: true)
end
end
2017-08-17 22:00:37 +05:30
end
end
2016-09-29 09:46:39 +05:30
2018-11-08 19:23:39 +05:30
describe '#default_environment' do
let(:project) { create(:project) }
it 'returns production environment when it exists' do
production = create(:environment, name: "production", project: project)
create(:environment, name: 'staging', project: project)
expect(project.default_environment).to eq(production)
end
it 'returns first environment when no production environment exists' do
create(:environment, name: 'staging', project: project)
create(:environment, name: 'foo', project: project)
expect(project.default_environment).to eq(project.environments.first)
end
it 'returns nil when no available environment exists' do
expect(project.default_environment).to be_nil
end
end
2018-12-13 13:39:08 +05:30
describe '#ci_variables_for' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2019-10-12 21:52:04 +05:30
let(:environment_scope) { '*' }
2017-09-10 17:25:29 +05:30
2018-12-13 13:39:08 +05:30
let!(:ci_variable) do
2019-10-12 21:52:04 +05:30
create(:ci_variable, value: 'secret', project: project, environment_scope: environment_scope)
2017-09-10 17:25:29 +05:30
end
let!(:protected_variable) do
create(:ci_variable, :protected, value: 'protected', project: project)
end
2018-12-13 13:39:08 +05:30
subject { project.reload.ci_variables_for(ref: 'ref') }
2017-09-10 17:25:29 +05:30
before do
stub_application_setting(
default_branch_protection: Gitlab::Access::PROTECTION_NONE)
end
shared_examples 'ref is protected' do
it 'contains all the variables' do
2018-12-13 13:39:08 +05:30
is_expected.to contain_exactly(ci_variable, protected_variable)
2017-09-10 17:25:29 +05:30
end
end
2020-04-08 14:13:33 +05:30
it 'memoizes the result by ref and environment', :request_store do
scoped_variable = create(:ci_variable, value: 'secret', project: project, environment_scope: 'scoped')
expect(project).to receive(:protected_for?).with('ref').once.and_return(true)
expect(project).to receive(:protected_for?).with('other').twice.and_return(false)
2.times do
expect(project.reload.ci_variables_for(ref: 'ref', environment: 'production')).to contain_exactly(ci_variable, protected_variable)
expect(project.reload.ci_variables_for(ref: 'other')).to contain_exactly(ci_variable)
expect(project.reload.ci_variables_for(ref: 'other', environment: 'scoped')).to contain_exactly(ci_variable, scoped_variable)
end
end
2017-09-10 17:25:29 +05:30
context 'when the ref is not protected' do
2019-01-03 12:48:30 +05:30
before do
allow(project).to receive(:protected_for?).with('ref').and_return(false)
end
2018-12-13 13:39:08 +05:30
it 'contains only the CI variables' do
is_expected.to contain_exactly(ci_variable)
2017-09-10 17:25:29 +05:30
end
end
context 'when the ref is a protected branch' do
before do
2018-03-17 18:26:18 +05:30
allow(project).to receive(:protected_for?).with('ref').and_return(true)
2017-09-10 17:25:29 +05:30
end
it_behaves_like 'ref is protected'
end
context 'when the ref is a protected tag' do
before do
2018-03-17 18:26:18 +05:30
allow(project).to receive(:protected_for?).with('ref').and_return(true)
2017-09-10 17:25:29 +05:30
end
it_behaves_like 'ref is protected'
end
2019-10-12 21:52:04 +05:30
context 'when environment name is specified' do
let(:environment) { 'review/name' }
subject do
project.ci_variables_for(ref: 'ref', environment: environment)
end
context 'when environment scope is exactly matched' do
let(:environment_scope) { 'review/name' }
it { is_expected.to contain_exactly(ci_variable) }
end
context 'when environment scope is matched by wildcard' do
let(:environment_scope) { 'review/*' }
it { is_expected.to contain_exactly(ci_variable) }
end
context 'when environment scope does not match' do
let(:environment_scope) { 'review/*/special' }
it { is_expected.not_to contain_exactly(ci_variable) }
end
context 'when environment scope has _' do
let(:environment_scope) { '*_*' }
it 'does not treat it as wildcard' do
is_expected.not_to contain_exactly(ci_variable)
end
context 'when environment name contains underscore' do
let(:environment) { 'foo_bar/test' }
let(:environment_scope) { 'foo_bar/*' }
it 'matches literally for _' do
is_expected.to contain_exactly(ci_variable)
end
end
end
# The environment name and scope cannot have % at the moment,
# but we're considering relaxing it and we should also make sure
# it doesn't break in case some data sneaked in somehow as we're
# not checking this integrity in database level.
context 'when environment scope has %' do
it 'does not treat it as wildcard' do
ci_variable.update_attribute(:environment_scope, '*%*')
is_expected.not_to contain_exactly(ci_variable)
end
context 'when environment name contains a percent' do
let(:environment) { 'foo%bar/test' }
it 'matches literally for _' do
ci_variable.update(environment_scope: 'foo%bar/*')
is_expected.to contain_exactly(ci_variable)
end
end
end
context 'when variables with the same name have different environment scopes' do
let!(:partially_matched_variable) do
create(:ci_variable,
key: ci_variable.key,
value: 'partial',
environment_scope: 'review/*',
project: project)
end
let!(:perfectly_matched_variable) do
create(:ci_variable,
key: ci_variable.key,
value: 'prefect',
environment_scope: 'review/name',
project: project)
end
it 'puts variables matching environment scope more in the end' do
is_expected.to eq(
[ci_variable,
partially_matched_variable,
perfectly_matched_variable])
end
end
end
2017-09-10 17:25:29 +05:30
end
2020-05-24 23:13:21 +05:30
describe '#ci_instance_variables_for' do
let(:project) { create(:project) }
let!(:instance_variable) do
create(:ci_instance_variable, value: 'secret')
end
let!(:protected_instance_variable) do
create(:ci_instance_variable, :protected, value: 'protected')
end
subject { project.ci_instance_variables_for(ref: 'ref') }
before do
stub_application_setting(
default_branch_protection: Gitlab::Access::PROTECTION_NONE)
end
context 'when the ref is not protected' do
before do
allow(project).to receive(:protected_for?).with('ref').and_return(false)
end
it 'contains only the CI variables' do
is_expected.to contain_exactly(instance_variable)
end
end
context 'when the ref is protected' do
before do
allow(project).to receive(:protected_for?).with('ref').and_return(true)
end
it 'contains all the variables' do
is_expected.to contain_exactly(instance_variable, protected_instance_variable)
end
end
end
2018-11-08 19:23:39 +05:30
describe '#any_lfs_file_locks?', :request_store do
2019-12-21 20:55:43 +05:30
let_it_be(:project) { create(:project) }
2018-11-08 19:23:39 +05:30
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
2017-09-10 17:25:29 +05:30
describe '#protected_for?' do
2019-01-03 12:48:30 +05:30
let(:project) { create(:project, :repository) }
2017-09-10 17:25:29 +05:30
2019-01-03 12:48:30 +05:30
subject { project.protected_for?(ref) }
2017-09-10 17:25:29 +05:30
2019-01-03 12:48:30 +05:30
shared_examples 'ref is not protected' do
2017-09-10 17:25:29 +05:30
before do
stub_application_setting(
default_branch_protection: Gitlab::Access::PROTECTION_NONE)
end
it 'returns false' do
2019-01-03 12:48:30 +05:30
is_expected.to be false
2017-09-10 17:25:29 +05:30
end
end
2019-01-03 12:48:30 +05:30
shared_examples 'ref is protected branch' do
2017-09-10 17:25:29 +05:30
before do
2019-01-03 12:48:30 +05:30
create(:protected_branch, name: 'master', project: project)
2017-09-10 17:25:29 +05:30
end
it 'returns true' do
2019-01-03 12:48:30 +05:30
is_expected.to be true
2017-09-10 17:25:29 +05:30
end
end
2019-01-03 12:48:30 +05:30
shared_examples 'ref is protected tag' do
2017-09-10 17:25:29 +05:30
before do
2019-01-03 12:48:30 +05:30
create(:protected_tag, name: 'v1.0.0', project: project)
2017-09-10 17:25:29 +05:30
end
it 'returns true' do
2019-01-03 12:48:30 +05:30
is_expected.to be true
end
end
context 'when ref is nil' do
let(:ref) { nil }
it 'returns false' do
is_expected.to be false
end
end
context 'when ref is ref name' do
context 'when ref is ambiguous' do
let(:ref) { 'ref' }
before do
project.repository.add_branch(project.creator, 'ref', 'master')
project.repository.add_tag(project.creator, 'ref', 'master')
end
it 'raises an error' do
expect { subject }.to raise_error(Repository::AmbiguousRefError)
end
end
context 'when the ref is not protected' do
let(:ref) { 'master' }
it_behaves_like 'ref is not protected'
end
context 'when the ref is a protected branch' do
let(:ref) { 'master' }
it_behaves_like 'ref is protected branch'
end
context 'when the ref is a protected tag' do
let(:ref) { 'v1.0.0' }
it_behaves_like 'ref is protected tag'
end
context 'when ref does not exist' do
let(:ref) { 'something' }
it 'returns false' do
is_expected.to be false
end
end
end
context 'when ref is full ref' do
context 'when the ref is not protected' do
let(:ref) { 'refs/heads/master' }
it_behaves_like 'ref is not protected'
end
context 'when the ref is a protected branch' do
let(:ref) { 'refs/heads/master' }
it_behaves_like 'ref is protected branch'
end
context 'when the ref is a protected tag' do
let(:ref) { 'refs/tags/v1.0.0' }
it_behaves_like 'ref is protected tag'
end
context 'when branch ref name is a full tag ref' do
let(:ref) { 'refs/tags/something' }
before do
project.repository.add_branch(project.creator, ref, 'master')
end
context 'when ref is not protected' do
it 'returns false' do
is_expected.to be false
end
end
context 'when ref is a protected branch' do
before do
create(:protected_branch, name: 'refs/tags/something', project: project)
end
it 'returns true' do
is_expected.to be true
end
end
end
context 'when ref does not exist' do
let(:ref) { 'refs/heads/something' }
it 'returns false' do
is_expected.to be false
end
2017-09-10 17:25:29 +05:30
end
end
end
2017-08-17 22:00:37 +05:30
describe '#update_project_statistics' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2017-08-17 22:00:37 +05:30
it "is called after creation" do
expect(project.statistics).to be_a ProjectStatistics
expect(project.statistics).to be_persisted
end
it "copies the namespace_id" do
expect(project.statistics.namespace_id).to eq project.namespace_id
end
it "updates the namespace_id when changed" do
namespace = create(:namespace)
project.update(namespace: namespace)
expect(project.statistics.namespace_id).to eq namespace.id
end
end
describe 'inside_path' do
2017-09-10 17:25:29 +05:30
let!(:project1) { create(:project, namespace: create(:namespace, path: 'name_pace')) }
let!(:project2) { create(:project) }
let!(:project3) { create(:project, namespace: create(:namespace, path: 'namespace')) }
2017-08-17 22:00:37 +05:30
let!(:path) { project1.namespace.full_path }
it 'returns correct project' do
2017-09-10 17:25:29 +05:30
expect(described_class.inside_path(path)).to eq([project1])
2017-08-17 22:00:37 +05:30
end
end
describe '#route_map_for' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project, :repository) }
2017-08-17 22:00:37 +05:30
let(:route_map) do
<<-MAP.strip_heredoc
- source: /source/(.*)/
public: '\\1'
MAP
end
before do
project.repository.create_file(User.last, '.gitlab/route-map.yml', route_map, message: 'Add .gitlab/route-map.yml', branch_name: 'master')
end
context 'when there is a .gitlab/route-map.yml at the commit' do
context 'when the route map is valid' do
it 'returns a route map' do
map = project.route_map_for(project.commit.sha)
expect(map).to be_a_kind_of(Gitlab::RouteMap)
end
2016-09-29 09:46:39 +05:30
end
2017-08-17 22:00:37 +05:30
context 'when the route map is invalid' do
let(:route_map) { 'INVALID' }
it 'returns nil' do
expect(project.route_map_for(project.commit.sha)).to be_nil
end
2016-09-29 09:46:39 +05:30
end
2017-08-17 22:00:37 +05:30
end
2016-09-29 09:46:39 +05:30
2017-08-17 22:00:37 +05:30
context 'when there is no .gitlab/route-map.yml at the commit' do
it 'returns nil' do
expect(project.route_map_for(project.commit.parent.sha)).to be_nil
2016-09-29 09:46:39 +05:30
end
end
2017-08-17 22:00:37 +05:30
end
2016-09-29 09:46:39 +05:30
2017-08-17 22:00:37 +05:30
describe '#public_path_for_source_path' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project, :repository) }
2017-08-17 22:00:37 +05:30
let(:route_map) do
Gitlab::RouteMap.new(<<-MAP.strip_heredoc)
- source: /source/(.*)/
public: '\\1'
MAP
end
2020-10-24 23:57:45 +05:30
2017-08-17 22:00:37 +05:30
let(:sha) { project.commit.id }
context 'when there is a route map' do
2016-09-29 09:46:39 +05:30
before do
2017-08-17 22:00:37 +05:30
allow(project).to receive(:route_map_for).with(sha).and_return(route_map)
2016-09-29 09:46:39 +05:30
end
2017-08-17 22:00:37 +05:30
context 'when the source path is mapped' do
it 'returns the public path' do
expect(project.public_path_for_source_path('source/file.html', sha)).to eq('file.html')
end
2016-09-29 09:46:39 +05:30
end
2017-08-17 22:00:37 +05:30
context 'when the source path is not mapped' do
it 'returns nil' do
expect(project.public_path_for_source_path('file.html', sha)).to be_nil
end
2016-09-29 09:46:39 +05:30
end
2019-10-12 21:52:04 +05:30
it 'returns a public path with a leading slash unmodified' do
route_map = Gitlab::RouteMap.new(<<-MAP.strip_heredoc)
- source: 'source/file.html'
public: '/public/file'
MAP
allow(project).to receive(:route_map_for).with(sha).and_return(route_map)
expect(project.public_path_for_source_path('source/file.html', sha)).to eq('/public/file')
end
2017-08-17 22:00:37 +05:30
end
2016-09-29 09:46:39 +05:30
2017-08-17 22:00:37 +05:30
context 'when there is no route map' do
before do
allow(project).to receive(:route_map_for).with(sha).and_return(nil)
end
it 'returns nil' do
expect(project.public_path_for_source_path('source/file.html', sha)).to be_nil
2016-09-29 09:46:39 +05:30
end
end
end
2017-08-17 22:00:37 +05:30
describe '#parent' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2017-08-17 22:00:37 +05:30
it { expect(project.parent).to eq(project.namespace) }
end
2018-03-17 18:26:18 +05:30
describe '#parent_id' do
let(:project) { create(:project) }
it { expect(project.parent_id).to eq(project.namespace_id) }
end
2017-08-17 22:00:37 +05:30
describe '#parent_changed?' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2017-08-17 22:00:37 +05:30
2017-09-10 17:25:29 +05:30
before do
project.namespace_id = 7
end
2017-08-17 22:00:37 +05:30
it { expect(project.parent_changed?).to be_truthy }
end
2020-01-01 13:55:28 +05:30
describe '#default_merge_request_target' do
context 'when forked from a more visible project' do
it 'returns the more restrictive project' do
project = create(:project, :public)
forked = fork_project(project)
forked.visibility = Gitlab::VisibilityLevel::PRIVATE
forked.save!
expect(project.visibility).to eq 'public'
expect(forked.visibility).to eq 'private'
expect(forked.default_merge_request_target).to eq(forked)
end
end
context 'when forked from a project with disabled merge requests' do
it 'returns the current project' do
project = create(:project, :merge_requests_disabled)
forked = fork_project(project)
expect(forked.forked_from_project).to receive(:merge_requests_enabled?)
.and_call_original
expect(forked.default_merge_request_target).to eq(forked)
end
end
context 'when forked from a project with enabled merge requests' do
it 'returns the source project' do
project = create(:project, :public)
forked = fork_project(project)
expect(project.visibility).to eq 'public'
expect(forked.visibility).to eq 'public'
expect(forked.default_merge_request_target).to eq(project)
end
end
context 'when not forked' do
it 'returns the current project' do
project = build_stubbed(:project)
expect(project.default_merge_request_target).to eq(project)
end
end
end
2016-09-29 09:46:39 +05:30
def enable_lfs
allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
end
2017-08-17 22:00:37 +05:30
describe '#pages_url' do
2018-11-08 19:23:39 +05:30
let(:group) { create(:group, name: 'Group') }
let(:nested_group) { create(:group, parent: group) }
2017-08-17 22:00:37 +05:30
let(:domain) { 'Example.com' }
subject { project.pages_url }
before do
allow(Settings.pages).to receive(:host).and_return(domain)
allow(Gitlab.config.pages).to receive(:url).and_return('http://example.com')
end
context 'top-level group' do
2018-11-08 19:23:39 +05:30
let(:project) { create(:project, namespace: group, name: project_name) }
2017-08-17 22:00:37 +05:30
context 'group page' do
let(:project_name) { 'group.example.com' }
it { is_expected.to eq("http://group.example.com") }
end
context 'project page' do
let(:project_name) { 'Project' }
it { is_expected.to eq("http://group.example.com/project") }
end
end
context 'nested group' do
2018-11-08 19:23:39 +05:30
let(:project) { create(:project, namespace: nested_group, name: project_name) }
2017-08-17 22:00:37 +05:30
let(:expected_url) { "http://group.example.com/#{nested_group.path}/#{project.path}" }
context 'group page' do
let(:project_name) { 'group.example.com' }
it { is_expected.to eq(expected_url) }
end
context 'project page' do
let(:project_name) { 'Project' }
it { is_expected.to eq(expected_url) }
end
end
end
2019-02-15 15:39:39 +05:30
describe '#lfs_http_url_to_repo' do
let(:project) { create(:project) }
2019-12-21 20:55:43 +05:30
context 'when a custom HTTP clone URL root is not set' do
it 'returns the url to the repo without a username' do
lfs_http_url_to_repo = project.lfs_http_url_to_repo('operation_that_doesnt_matter')
expect(lfs_http_url_to_repo).to eq("#{project.web_url}.git")
expect(lfs_http_url_to_repo).not_to include('@')
end
end
context 'when a custom HTTP clone URL root is set' do
before do
stub_application_setting(custom_http_clone_url_root: 'https://git.example.com:51234')
end
2019-02-15 15:39:39 +05:30
2019-12-21 20:55:43 +05:30
it 'returns the url to the repo, with the root replaced with the custom one' do
lfs_http_url_to_repo = project.lfs_http_url_to_repo('operation_that_doesnt_matter')
expect(lfs_http_url_to_repo).to eq("https://git.example.com:51234/#{project.full_path}.git")
end
2019-02-15 15:39:39 +05:30
end
end
2017-08-17 22:00:37 +05:30
describe '#pipeline_status' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project, :repository) }
2020-03-13 15:44:24 +05:30
2017-08-17 22:00:37 +05:30
it 'builds a pipeline status' do
expect(project.pipeline_status).to be_a(Gitlab::Cache::Ci::ProjectPipelineStatus)
end
it 'hase a loaded pipeline status' do
expect(project.pipeline_status).to be_loaded
end
end
2019-02-15 15:39:39 +05:30
describe '#update' do
let(:project) { create(:project) }
it 'validates the visibility' do
expect(project).to receive(:visibility_level_allowed_as_fork).and_call_original
expect(project).to receive(:visibility_level_allowed_by_group).and_call_original
project.update(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
end
it 'does not validate the visibility' do
expect(project).not_to receive(:visibility_level_allowed_as_fork).and_call_original
expect(project).not_to receive(:visibility_level_allowed_by_group).and_call_original
2020-06-23 00:09:42 +05:30
project.update(updated_at: Time.current)
2019-02-15 15:39:39 +05:30
end
end
2017-08-17 22:00:37 +05:30
describe '#last_repository_updated_at' do
it 'sets to created_at upon creation' do
2017-09-10 17:25:29 +05:30
project = create(:project, created_at: 2.hours.ago)
2017-08-17 22:00:37 +05:30
expect(project.last_repository_updated_at.to_i).to eq(project.created_at.to_i)
end
end
2017-09-10 17:25:29 +05:30
describe '.public_or_visible_to_user' do
let!(:user) { create(:user) }
let!(:private_project) do
create(:project, :private, creator: user, namespace: user.namespace)
end
let!(:public_project) { create(:project, :public) }
context 'with a user' do
let(:projects) do
described_class.all.public_or_visible_to_user(user)
end
it 'includes projects the user has access to' do
expect(projects).to include(private_project)
end
it 'includes projects the user can see' do
expect(projects).to include(public_project)
end
end
context 'without a user' do
it 'only includes public projects' do
projects = described_class.all.public_or_visible_to_user
expect(projects).to eq([public_project])
end
end
2019-12-04 20:38:33 +05:30
context 'min_access_level' do
let!(:private_project) { create(:project, :private) }
before do
private_project.add_guest(user)
end
it 'excludes projects when user does not have required minimum access level' do
projects = described_class.all.public_or_visible_to_user(user, Gitlab::Access::REPORTER)
expect(projects).to contain_exactly(public_project)
end
end
2020-05-24 23:13:21 +05:30
context 'with deploy token users' do
let_it_be(:private_project) { create(:project, :private) }
subject { described_class.all.public_or_visible_to_user(user) }
context 'deploy token user without project' do
let_it_be(:user) { create(:deploy_token) }
it { is_expected.to eq [] }
end
context 'deploy token user with project' do
let_it_be(:user) { create(:deploy_token, projects: [private_project]) }
it { is_expected.to include(private_project) }
end
end
2017-09-10 17:25:29 +05:30
end
2019-10-31 01:37:42 +05:30
describe '.ids_with_issuables_available_for' do
2019-06-05 12:25:43 +05:30
let!(:user) { create(:user) }
it 'returns project ids with milestones available for user' do
project_1 = create(:project, :public, :merge_requests_disabled, :issues_disabled)
project_2 = create(:project, :public, :merge_requests_disabled)
project_3 = create(:project, :public, :issues_disabled)
project_4 = create(:project, :public)
project_4.project_feature.update(issues_access_level: ProjectFeature::PRIVATE, merge_requests_access_level: ProjectFeature::PRIVATE )
2019-10-31 01:37:42 +05:30
project_ids = described_class.ids_with_issuables_available_for(user).pluck(:id)
2019-06-05 12:25:43 +05:30
expect(project_ids).to include(project_2.id, project_3.id)
expect(project_ids).not_to include(project_1.id, project_4.id)
end
end
2019-02-15 15:39:39 +05:30
describe '.with_feature_available_for_user' do
2019-07-07 11:18:12 +05:30
let(:user) { create(:user) }
let(:feature) { MergeRequest }
2019-02-15 15:39:39 +05:30
subject { described_class.with_feature_available_for_user(feature, user) }
2019-07-07 11:18:12 +05:30
shared_examples 'feature disabled' do
let(:project) { create(:project, :public, :merge_requests_disabled) }
it 'does not return projects with the project feature disabled' do
is_expected.not_to include(project)
end
end
shared_examples 'feature public' do
let(:project) { create(:project, :public, :merge_requests_public) }
it 'returns projects with the project feature public' do
is_expected.to include(project)
end
end
2019-02-15 15:39:39 +05:30
2019-07-07 11:18:12 +05:30
shared_examples 'feature enabled' do
let(:project) { create(:project, :public, :merge_requests_enabled) }
it 'returns projects with the project feature enabled' do
is_expected.to include(project)
end
end
shared_examples 'feature access level is nil' do
let(:project) { create(:project, :public) }
it 'returns projects with the project feature access level nil' do
project.project_feature.update(merge_requests_access_level: nil)
is_expected.to include(project)
end
end
context 'with user' do
2019-02-15 15:39:39 +05:30
before do
project.add_guest(user)
end
2019-07-07 11:18:12 +05:30
it_behaves_like 'feature disabled'
it_behaves_like 'feature public'
it_behaves_like 'feature enabled'
it_behaves_like 'feature access level is nil'
context 'when feature is private' do
let(:project) { create(:project, :public, :merge_requests_private) }
2020-06-23 00:09:42 +05:30
context 'when user does not have access to the feature' do
2019-07-07 11:18:12 +05:30
it 'does not return projects with the project feature private' do
is_expected.not_to include(project)
2019-02-15 15:39:39 +05:30
end
end
2019-07-07 11:18:12 +05:30
context 'when user has access to the feature' do
it 'returns projects with the project feature private' do
project.add_reporter(user)
2019-02-15 15:39:39 +05:30
is_expected.to include(project)
end
end
end
2019-07-07 11:18:12 +05:30
end
2019-02-15 15:39:39 +05:30
2019-07-07 11:18:12 +05:30
context 'user is an admin' do
let(:user) { create(:user, :admin) }
2019-02-15 15:39:39 +05:30
2019-07-07 11:18:12 +05:30
it_behaves_like 'feature disabled'
it_behaves_like 'feature public'
it_behaves_like 'feature enabled'
it_behaves_like 'feature access level is nil'
2019-02-15 15:39:39 +05:30
2019-07-07 11:18:12 +05:30
context 'when feature is private' do
let(:project) { create(:project, :public, :merge_requests_private) }
2019-02-15 15:39:39 +05:30
2019-07-07 11:18:12 +05:30
it 'returns projects with the project feature private' do
is_expected.to include(project)
2019-02-15 15:39:39 +05:30
end
end
end
2019-07-07 11:18:12 +05:30
context 'without user' do
let(:user) { nil }
2019-02-15 15:39:39 +05:30
2019-07-07 11:18:12 +05:30
it_behaves_like 'feature disabled'
it_behaves_like 'feature public'
it_behaves_like 'feature enabled'
it_behaves_like 'feature access level is nil'
context 'when feature is private' do
let(:project) { create(:project, :public, :merge_requests_private) }
it 'does not return projects with the project feature private' do
is_expected.not_to include(project)
end
2019-02-15 15:39:39 +05:30
end
end
end
2020-05-24 23:13:21 +05:30
describe '.filter_by_feature_visibility', :enable_admin_mode do
2019-10-03 12:08:05 +05:30
include_context 'ProjectPolicyTable context'
include ProjectHelpers
using RSpec::Parameterized::TableSyntax
2019-12-21 20:55:43 +05:30
let_it_be(:group) { create(:group) }
2019-10-03 12:08:05 +05:30
let!(:project) { create(:project, project_level, namespace: group ) }
let(:user) { create_user_from_membership(project, membership) }
context 'reporter level access' do
let(:feature) { MergeRequest }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_reporter_feature_access
end
with_them do
it "respects visibility" do
update_feature_access_level(project, feature_access_level)
expected_objects = expected_count == 1 ? [project] : []
expect(
described_class.filter_by_feature_visibility(feature, user)
).to eq(expected_objects)
end
end
end
2019-12-04 20:38:33 +05:30
context 'issues' do
let(:feature) { Issue }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access
end
with_them do
it "respects visibility" do
update_feature_access_level(project, feature_access_level)
expected_objects = expected_count == 1 ? [project] : []
expect(
described_class.filter_by_feature_visibility(feature, user)
).to eq(expected_objects)
end
end
end
context 'wiki' do
let(:feature) { :wiki }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access
end
with_them do
it "respects visibility" do
update_feature_access_level(project, feature_access_level)
expected_objects = expected_count == 1 ? [project] : []
expect(
described_class.filter_by_feature_visibility(feature, user)
).to eq(expected_objects)
end
end
end
context 'code' do
let(:feature) { :repository }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access_and_non_private_project_only
end
with_them do
it "respects visibility" do
update_feature_access_level(project, feature_access_level)
expected_objects = expected_count == 1 ? [project] : []
expect(
described_class.filter_by_feature_visibility(feature, user)
).to eq(expected_objects)
end
end
end
2019-10-03 12:08:05 +05:30
end
2020-03-13 15:44:24 +05:30
describe '.wrap_with_cte' do
let!(:user) { create(:user) }
let!(:private_project) do
create(:project, :private, creator: user, namespace: user.namespace)
end
let!(:public_project) { create(:project, :public) }
let(:projects) { described_class.all.public_or_visible_to_user(user) }
subject { described_class.wrap_with_cte(projects) }
it 'wrapped query matches original' do
expect(subject.to_sql).to match(/^WITH "projects_cte" AS/)
expect(subject).to match_array(projects)
end
end
2018-03-17 18:26:18 +05:30
describe '#pages_available?' do
let(:project) { create(:project, group: group) }
subject { project.pages_available? }
before do
allow(Gitlab.config.pages).to receive(:enabled).and_return(true)
end
context 'when the project is in a top level namespace' do
let(:group) { create(:group) }
it { is_expected.to be(true) }
end
context 'when the project is in a subgroup' do
let(:group) { create(:group, :nested) }
2019-03-02 22:35:43 +05:30
it { is_expected.to be(true) }
2018-03-17 18:26:18 +05:30
end
end
2017-09-10 17:25:29 +05:30
describe '#remove_private_deploy_keys' do
let!(:project) { create(:project) }
context 'for a private deploy key' do
let!(:key) { create(:deploy_key, public: false) }
let!(:deploy_keys_project) { create(:deploy_keys_project, deploy_key: key, project: project) }
context 'when the key is not linked to another project' do
it 'removes the key' do
project.remove_private_deploy_keys
expect(project.deploy_keys).not_to include(key)
end
end
context 'when the key is linked to another project' do
before do
another_project = create(:project)
create(:deploy_keys_project, deploy_key: key, project: another_project)
end
it 'does not remove the key' do
project.remove_private_deploy_keys
expect(project.deploy_keys).to include(key)
end
end
end
context 'for a public deploy key' do
let!(:key) { create(:deploy_key, public: true) }
let!(:deploy_keys_project) { create(:deploy_keys_project, deploy_key: key, project: project) }
it 'does not remove the key' do
project.remove_private_deploy_keys
expect(project.deploy_keys).to include(key)
end
end
end
describe '#remove_pages' do
2019-12-21 20:55:43 +05:30
let(:project) { create(:project).tap { |project| project.mark_pages_as_deployed } }
let(:pages_metadatum) { project.pages_metadatum }
2017-09-10 17:25:29 +05:30
let(:namespace) { project.namespace }
let(:pages_path) { project.pages_path }
around do |example|
FileUtils.mkdir_p(pages_path)
begin
example.run
ensure
FileUtils.rm_rf(pages_path)
end
end
2019-12-21 20:55:43 +05:30
it 'removes the pages directory and marks the project as not having pages deployed' do
2017-09-10 17:25:29 +05:30
expect_any_instance_of(Gitlab::PagesTransfer).to receive(:rename_project).and_return(true)
expect(PagesWorker).to receive(:perform_in).with(5.minutes, :remove, namespace.full_path, anything)
2019-12-21 20:55:43 +05:30
expect { project.remove_pages }.to change { pages_metadatum.reload.deployed }.from(true).to(false)
2017-09-10 17:25:29 +05:30
end
it 'is run when the project is destroyed' do
expect(project).to receive(:remove_pages).and_call_original
2019-12-21 20:55:43 +05:30
expect { project.destroy }.not_to raise_error
2017-09-10 17:25:29 +05:30
end
end
2018-05-09 12:01:36 +05:30
describe '#remove_export' do
2018-03-17 18:26:18 +05:30
let(:project) { create(:project, :with_export) }
2020-04-08 14:13:33 +05:30
before do
allow_next_instance_of(ProjectExportWorker) do |job|
allow(job).to receive(:jid).and_return(SecureRandom.hex(8))
end
end
2018-11-20 20:47:30 +05:30
it 'removes the export' do
2018-03-27 19:54:05 +05:30
project.remove_exports
2018-11-20 20:47:30 +05:30
expect(project.export_file_exists?).to be_falsey
2018-05-09 12:01:36 +05:30
end
end
2017-09-10 17:25:29 +05:30
describe '#forks_count' do
it 'returns the number of forks' do
project = build(:project)
2020-07-28 23:09:34 +05:30
expect_any_instance_of(::Projects::BatchForksCountService).to receive(:refresh_cache_and_retrieve_data).and_return({ project => 1 })
2017-09-10 17:25:29 +05:30
expect(project.forks_count).to eq(1)
end
end
2018-03-17 18:26:18 +05:30
2019-02-15 15:39:39 +05:30
describe '#git_transfer_in_progress?' do
let(:project) { build(:project) }
subject { project.git_transfer_in_progress? }
it 'returns false when repo_reference_count and wiki_reference_count are 0' do
allow(project).to receive(:repo_reference_count) { 0 }
allow(project).to receive(:wiki_reference_count) { 0 }
expect(subject).to be_falsey
end
it 'returns true when repo_reference_count is > 0' do
allow(project).to receive(:repo_reference_count) { 2 }
allow(project).to receive(:wiki_reference_count) { 0 }
expect(subject).to be_truthy
end
it 'returns true when wiki_reference_count is > 0' do
allow(project).to receive(:repo_reference_count) { 0 }
allow(project).to receive(:wiki_reference_count) { 2 }
expect(subject).to be_truthy
end
end
2018-03-17 18:26:18 +05:30
context 'legacy storage' do
2020-03-13 15:44:24 +05:30
let_it_be(:project) { create(:project, :repository, :legacy_storage) }
2018-03-17 18:26:18 +05:30
let(:gitlab_shell) { Gitlab::Shell.new }
let(:project_storage) { project.send(:storage) }
before do
allow(project).to receive(:gitlab_shell).and_return(gitlab_shell)
2019-09-04 21:01:54 +05:30
stub_application_setting(hashed_storage_enabled: false)
2018-03-17 18:26:18 +05:30
end
describe '#base_dir' do
it 'returns base_dir based on namespace only' do
expect(project.base_dir).to eq(project.namespace.full_path)
end
end
describe '#disk_path' do
it 'returns disk_path based on namespace and project path' do
expect(project.disk_path).to eq("#{project.namespace.full_path}/#{project.path}")
end
end
describe '#legacy_storage?' do
it 'returns true when storage_version is nil' do
project = build(:project, storage_version: nil)
expect(project.legacy_storage?).to be_truthy
end
it 'returns true when the storage_version is 0' do
project = build(:project, storage_version: 0)
expect(project.legacy_storage?).to be_truthy
end
end
describe '#hashed_storage?' do
it 'returns false' do
expect(project.hashed_storage?(:repository)).to be_falsey
end
end
describe '#pages_path' do
it 'returns a path where pages are stored' do
expect(project.pages_path).to eq(File.join(Settings.pages.path, project.namespace.full_path, project.path))
end
end
describe '#migrate_to_hashed_storage!' do
2019-03-02 22:35:43 +05:30
let(:project) { create(:project, :empty_repo, :legacy_storage) }
2018-03-17 18:26:18 +05:30
it 'returns true' do
expect(project.migrate_to_hashed_storage!).to be_truthy
end
2019-03-02 22:35:43 +05:30
it 'does not run validation' do
expect(project).not_to receive(:valid?)
2019-02-15 15:39:39 +05:30
project.migrate_to_hashed_storage!
2018-03-17 18:26:18 +05:30
end
2019-07-07 11:18:12 +05:30
it 'schedules HashedStorage::ProjectMigrateWorker with delayed start when the project repo is in use' do
2020-03-13 15:44:24 +05:30
Gitlab::ReferenceCounter.new(Gitlab::GlRepository::PROJECT.identifier_for_container(project)).increase
2018-03-17 18:26:18 +05:30
2019-07-07 11:18:12 +05:30
expect(HashedStorage::ProjectMigrateWorker).to receive(:perform_in)
2018-03-17 18:26:18 +05:30
project.migrate_to_hashed_storage!
end
2019-07-07 11:18:12 +05:30
it 'schedules HashedStorage::ProjectMigrateWorker with delayed start when the wiki repo is in use' do
2020-03-13 15:44:24 +05:30
Gitlab::ReferenceCounter.new(Gitlab::GlRepository::WIKI.identifier_for_container(project)).increase
2018-03-17 18:26:18 +05:30
2019-07-07 11:18:12 +05:30
expect(HashedStorage::ProjectMigrateWorker).to receive(:perform_in)
2018-03-17 18:26:18 +05:30
project.migrate_to_hashed_storage!
end
2019-07-07 11:18:12 +05:30
it 'schedules HashedStorage::ProjectMigrateWorker' do
expect(HashedStorage::ProjectMigrateWorker).to receive(:perform_async).with(project.id)
2018-03-17 18:26:18 +05:30
project.migrate_to_hashed_storage!
end
end
2019-07-07 11:18:12 +05:30
describe '#rollback_to_legacy_storage!' do
let(:project) { create(:project, :empty_repo, :legacy_storage) }
it 'returns nil' do
expect(project.rollback_to_legacy_storage!).to be_nil
end
it 'does not run validations' do
expect(project).not_to receive(:valid?)
project.rollback_to_legacy_storage!
end
end
2018-03-17 18:26:18 +05:30
end
context 'hashed storage' do
2020-03-13 15:44:24 +05:30
let_it_be(:project) { create(:project, :repository, skip_disk_validation: true) }
2018-03-17 18:26:18 +05:30
let(:gitlab_shell) { Gitlab::Shell.new }
let(:hash) { Digest::SHA2.hexdigest(project.id.to_s) }
2018-03-27 19:54:05 +05:30
let(:hashed_prefix) { File.join('@hashed', hash[0..1], hash[2..3]) }
let(:hashed_path) { File.join(hashed_prefix, hash) }
2018-03-17 18:26:18 +05:30
describe '#legacy_storage?' do
it 'returns false' do
expect(project.legacy_storage?).to be_falsey
end
end
describe '#hashed_storage?' do
it 'returns true if rolled out' do
expect(project.hashed_storage?(:attachments)).to be_truthy
end
it 'returns false when not rolled out yet' do
project.storage_version = 1
expect(project.hashed_storage?(:attachments)).to be_falsey
end
end
describe '#base_dir' do
it 'returns base_dir based on hash of project id' do
2018-03-27 19:54:05 +05:30
expect(project.base_dir).to eq(hashed_prefix)
2018-03-17 18:26:18 +05:30
end
end
describe '#disk_path' do
it 'returns disk_path based on hash of project id' do
expect(project.disk_path).to eq(hashed_path)
end
end
describe '#pages_path' do
it 'returns a path where pages are stored' do
expect(project.pages_path).to eq(File.join(Settings.pages.path, project.namespace.full_path, project.path))
end
end
describe '#migrate_to_hashed_storage!' do
2019-03-02 22:35:43 +05:30
let(:project) { create(:project, :repository, skip_disk_validation: true) }
2018-03-17 18:26:18 +05:30
it 'returns nil' do
expect(project.migrate_to_hashed_storage!).to be_nil
end
it 'does not flag as read-only' do
expect { project.migrate_to_hashed_storage! }.not_to change { project.repository_read_only }
end
2019-02-15 15:39:39 +05:30
context 'when partially migrated' do
2019-03-02 22:35:43 +05:30
it 'enqueues a job' do
2019-02-15 15:39:39 +05:30
project = create(:project, storage_version: 1, skip_disk_validation: true)
2019-03-02 22:35:43 +05:30
Sidekiq::Testing.fake! do
2019-07-07 11:18:12 +05:30
expect { project.migrate_to_hashed_storage! }.to change(HashedStorage::ProjectMigrateWorker.jobs, :size).by(1)
2019-03-02 22:35:43 +05:30
end
2019-02-15 15:39:39 +05:30
end
end
2018-03-17 18:26:18 +05:30
end
2019-07-07 11:18:12 +05:30
describe '#rollback_to_legacy_storage!' do
let(:project) { create(:project, :repository, skip_disk_validation: true) }
it 'returns true' do
expect(project.rollback_to_legacy_storage!).to be_truthy
end
it 'does not run validations' do
expect(project).not_to receive(:valid?)
2019-05-18 00:54:41 +05:30
2019-07-07 11:18:12 +05:30
project.rollback_to_legacy_storage!
end
it 'does not flag as read-only' do
expect { project.rollback_to_legacy_storage! }.not_to change { project.repository_read_only }
end
2018-03-17 18:26:18 +05:30
2019-07-07 11:18:12 +05:30
it 'enqueues a job' do
Sidekiq::Testing.fake! do
expect { project.rollback_to_legacy_storage! }.to change(HashedStorage::ProjectRollbackWorker.jobs, :size).by(1)
end
end
2018-03-17 18:26:18 +05:30
end
end
describe '#has_ci?' do
2020-03-13 15:44:24 +05:30
let_it_be(:project, reload: true) { create(:project) }
2018-03-17 18:26:18 +05:30
let(:repository) { double }
before do
expect(project).to receive(:repository) { repository }
end
context 'when has .gitlab-ci.yml' do
before do
expect(repository).to receive(:gitlab_ci_yml) { 'content' }
end
it "CI is available" do
expect(project).to have_ci
end
end
context 'when there is no .gitlab-ci.yml' do
before do
expect(repository).to receive(:gitlab_ci_yml) { nil }
end
2018-11-20 20:47:30 +05:30
it "CI is available" do
expect(project).to have_ci
2018-03-17 18:26:18 +05:30
end
2018-11-20 20:47:30 +05:30
context 'when auto devops is disabled' do
2018-03-17 18:26:18 +05:30
before do
2018-11-20 20:47:30 +05:30
stub_application_setting(auto_devops_enabled: false)
2018-03-17 18:26:18 +05:30
end
2018-11-20 20:47:30 +05:30
it "CI is not available" do
expect(project).not_to have_ci
2018-03-17 18:26:18 +05:30
end
end
end
end
describe '#auto_devops_enabled?' do
2018-11-20 20:47:30 +05:30
before do
2020-06-23 00:09:42 +05:30
Feature.enable_percentage_of_actors(:force_autodevops_on_by_default, 0)
2018-11-20 20:47:30 +05:30
end
2020-03-13 15:44:24 +05:30
let_it_be(:project, reload: true) { create(:project) }
2018-03-17 18:26:18 +05:30
subject { project.auto_devops_enabled? }
2019-07-07 11:18:12 +05:30
context 'when explicitly enabled' do
before do
create(:project_auto_devops, project: project)
end
it { is_expected.to be_truthy }
end
context 'when explicitly disabled' do
before do
create(:project_auto_devops, project: project, enabled: false)
end
it { is_expected.to be_falsey }
end
2018-03-17 18:26:18 +05:30
context 'when enabled in settings' do
before do
stub_application_setting(auto_devops_enabled: true)
end
2018-11-20 20:47:30 +05:30
it { is_expected.to be_truthy }
2019-07-07 11:18:12 +05:30
end
context 'when disabled in settings' do
before do
stub_application_setting(auto_devops_enabled: false)
end
it { is_expected.to be_falsey }
2018-03-17 18:26:18 +05:30
context 'when explicitly enabled' do
before do
create(:project_auto_devops, project: project)
end
2018-11-20 20:47:30 +05:30
it { is_expected.to be_truthy }
2018-03-17 18:26:18 +05:30
end
context 'when explicitly disabled' do
before do
2019-07-07 11:18:12 +05:30
create(:project_auto_devops, :disabled, project: project)
2018-03-17 18:26:18 +05:30
end
2018-11-20 20:47:30 +05:30
it { is_expected.to be_falsey }
2018-03-17 18:26:18 +05:30
end
end
2019-07-07 11:18:12 +05:30
context 'when force_autodevops_on_by_default is enabled for the project' do
it { is_expected.to be_truthy }
end
context 'with group parents' do
let(:instance_enabled) { true }
2018-03-17 18:26:18 +05:30
before do
2019-07-07 11:18:12 +05:30
stub_application_setting(auto_devops_enabled: instance_enabled)
project.update!(namespace: parent_group)
2019-05-18 00:54:41 +05:30
end
2019-07-07 11:18:12 +05:30
context 'when enabled on parent' do
let(:parent_group) { create(:group, :auto_devops_enabled) }
2019-05-18 00:54:41 +05:30
2019-07-07 11:18:12 +05:30
context 'when auto devops instance enabled' do
it { is_expected.to be_truthy }
2019-05-18 00:54:41 +05:30
end
2019-07-07 11:18:12 +05:30
context 'when auto devops instance disabled' do
let(:instance_disabled) { false }
it { is_expected.to be_truthy }
end
2019-05-18 00:54:41 +05:30
end
2019-07-07 11:18:12 +05:30
context 'when disabled on parent' do
let(:parent_group) { create(:group, :auto_devops_disabled) }
context 'when auto devops instance enabled' do
it { is_expected.to be_falsy }
2019-05-18 00:54:41 +05:30
end
2019-07-07 11:18:12 +05:30
context 'when auto devops instance disabled' do
let(:instance_disabled) { false }
it { is_expected.to be_falsy }
end
end
2019-10-12 21:52:04 +05:30
context 'when enabled on root parent' do
2019-07-07 11:18:12 +05:30
let(:parent_group) { create(:group, parent: create(:group, :auto_devops_enabled)) }
context 'when auto devops instance enabled' do
it { is_expected.to be_truthy }
end
context 'when auto devops instance disabled' do
let(:instance_disabled) { false }
it { is_expected.to be_truthy }
end
context 'when explicitly disabled on parent' do
let(:parent_group) { create(:group, :auto_devops_disabled, parent: create(:group, :auto_devops_enabled)) }
it { is_expected.to be_falsy }
end
end
2019-10-12 21:52:04 +05:30
context 'when disabled on root parent' do
2019-07-07 11:18:12 +05:30
let(:parent_group) { create(:group, parent: create(:group, :auto_devops_disabled)) }
context 'when auto devops instance enabled' do
it { is_expected.to be_falsy }
end
context 'when auto devops instance disabled' do
let(:instance_disabled) { false }
it { is_expected.to be_falsy }
end
context 'when explicitly disabled on parent' do
let(:parent_group) { create(:group, :auto_devops_disabled, parent: create(:group, :auto_devops_enabled)) }
it { is_expected.to be_falsy }
end
2018-03-17 18:26:18 +05:30
end
end
end
2018-11-18 11:00:15 +05:30
describe '#has_auto_devops_implicitly_enabled?' do
2020-03-13 15:44:24 +05:30
let_it_be(:project, reload: true) { create(:project) }
2018-11-18 11:00:15 +05:30
context 'when disabled in settings' do
before do
stub_application_setting(auto_devops_enabled: false)
end
it 'does not have auto devops implicitly disabled' do
expect(project).not_to have_auto_devops_implicitly_enabled
end
end
context 'when enabled in settings' do
before do
stub_application_setting(auto_devops_enabled: true)
end
it 'auto devops is implicitly disabled' do
expect(project).to have_auto_devops_implicitly_enabled
end
context 'when explicitly disabled' do
before do
create(:project_auto_devops, project: project, enabled: false)
end
it 'does not have auto devops implicitly disabled' do
expect(project).not_to have_auto_devops_implicitly_enabled
end
end
context 'when explicitly enabled' do
before do
create(:project_auto_devops, project: project, enabled: true)
end
it 'does not have auto devops implicitly disabled' do
expect(project).not_to have_auto_devops_implicitly_enabled
end
end
end
2019-07-07 11:18:12 +05:30
context 'when enabled on group' do
it 'has auto devops implicitly enabled' do
project.update(namespace: create(:group, :auto_devops_enabled))
expect(project).to have_auto_devops_implicitly_enabled
end
end
context 'when enabled on parent group' do
it 'has auto devops implicitly enabled' do
subgroup = create(:group, parent: create(:group, :auto_devops_enabled))
project.update(namespace: subgroup)
expect(project).to have_auto_devops_implicitly_enabled
end
end
2018-11-18 11:00:15 +05:30
end
2018-03-17 18:26:18 +05:30
describe '#has_auto_devops_implicitly_disabled?' do
2020-03-13 15:44:24 +05:30
let_it_be(:project, reload: true) { create(:project) }
2019-07-07 11:18:12 +05:30
2018-11-20 20:47:30 +05:30
before do
2020-06-23 00:09:42 +05:30
Feature.enable_percentage_of_actors(:force_autodevops_on_by_default, 0)
2018-11-20 20:47:30 +05:30
end
2019-07-07 11:18:12 +05:30
context 'when explicitly disabled' do
before do
create(:project_auto_devops, project: project, enabled: false)
end
it 'does not have auto devops implicitly disabled' do
expect(project).not_to have_auto_devops_implicitly_disabled
end
end
context 'when explicitly enabled' do
before do
create(:project_auto_devops, project: project, enabled: true)
end
it 'does not have auto devops implicitly disabled' do
expect(project).not_to have_auto_devops_implicitly_disabled
end
end
2018-03-17 18:26:18 +05:30
context 'when enabled in settings' do
before do
stub_application_setting(auto_devops_enabled: true)
end
it 'does not have auto devops implicitly disabled' do
expect(project).not_to have_auto_devops_implicitly_disabled
end
end
context 'when disabled in settings' do
before do
stub_application_setting(auto_devops_enabled: false)
end
it 'auto devops is implicitly disabled' do
expect(project).to have_auto_devops_implicitly_disabled
end
2018-11-20 20:47:30 +05:30
context 'when force_autodevops_on_by_default is enabled for the project' do
before do
2019-07-07 11:18:12 +05:30
create(:project_auto_devops, project: project, enabled: false)
2020-06-23 00:09:42 +05:30
Feature.enable_percentage_of_actors(:force_autodevops_on_by_default, 100)
2018-11-20 20:47:30 +05:30
end
it 'does not have auto devops implicitly disabled' do
expect(project).not_to have_auto_devops_implicitly_disabled
end
end
2019-07-07 11:18:12 +05:30
context 'when disabled on group' do
it 'has auto devops implicitly disabled' do
project.update!(namespace: create(:group, :auto_devops_disabled))
2018-03-17 18:26:18 +05:30
2019-07-07 11:18:12 +05:30
expect(project).to have_auto_devops_implicitly_disabled
2018-03-17 18:26:18 +05:30
end
end
2019-07-07 11:18:12 +05:30
context 'when disabled on parent group' do
it 'has auto devops implicitly disabled' do
subgroup = create(:group, parent: create(:group, :auto_devops_disabled))
project.update!(namespace: subgroup)
2018-03-17 18:26:18 +05:30
2019-07-07 11:18:12 +05:30
expect(project).to have_auto_devops_implicitly_disabled
2018-03-17 18:26:18 +05:30
end
end
end
end
2019-02-15 15:39:39 +05:30
describe '#api_variables' do
2020-03-13 15:44:24 +05:30
let_it_be(:project) { create(:project) }
2019-02-15 15:39:39 +05:30
it 'exposes API v4 URL' do
expect(project.api_variables.first[:key]).to eq 'CI_API_V4_URL'
expect(project.api_variables.first[:value]).to include '/api/v4'
end
it 'contains a URL variable for every supported API version' do
# Ensure future API versions have proper variables defined. We're not doing this for v3.
supported_versions = API::API.versions - ['v3']
supported_versions = supported_versions.select do |version|
API::API.routes.select { |route| route.version == version }.many?
end
required_variables = supported_versions.map do |version|
"CI_API_#{version.upcase}_URL"
end
expect(project.api_variables.map { |variable| variable[:key] })
.to contain_exactly(*required_variables)
end
end
2018-03-17 18:26:18 +05:30
describe '#latest_successful_builds_for' do
let(:project) { build(:project) }
before do
allow(project).to receive(:default_branch).and_return('master')
end
context 'without a ref' do
it 'returns a pipeline for the default branch' do
expect(project)
.to receive(:latest_successful_pipeline_for_default_branch)
project.latest_successful_pipeline_for
end
end
context 'with the ref set to the default branch' do
it 'returns a pipeline for the default branch' do
expect(project)
.to receive(:latest_successful_pipeline_for_default_branch)
project.latest_successful_pipeline_for(project.default_branch)
end
end
context 'with a ref that is not the default branch' do
it 'returns the latest successful pipeline for the given ref' do
2019-10-12 21:52:04 +05:30
expect(project.ci_pipelines).to receive(:latest_successful_for_ref).with('foo')
2018-03-17 18:26:18 +05:30
project.latest_successful_pipeline_for('foo')
end
end
end
describe '#check_repository_path_availability' do
2019-12-21 20:55:43 +05:30
let(:project) { build(:project, :repository, :legacy_storage) }
context 'when the repository already exists' do
let(:project) { create(:project, :repository, :legacy_storage) }
2019-12-26 22:10:19 +05:30
it 'returns false when repository already exists' do
expect(project.check_repository_path_availability).to be_falsey
end
2019-12-21 20:55:43 +05:30
end
context 'when the repository does not exist' do
2019-12-26 22:10:19 +05:30
it 'returns false when repository already exists' do
expect(project.check_repository_path_availability).to be_truthy
end
2018-03-17 18:26:18 +05:30
2019-12-21 20:55:43 +05:30
it 'skips gitlab-shell exists?' do
project.skip_disk_validation = true
2018-03-17 18:26:18 +05:30
2019-12-21 20:55:43 +05:30
expect(project.gitlab_shell).not_to receive(:repository_exists?)
2019-12-26 22:10:19 +05:30
expect(project.check_repository_path_availability).to be_truthy
2019-12-21 20:55:43 +05:30
end
2018-03-17 18:26:18 +05:30
end
end
describe '#latest_successful_pipeline_for_default_branch' do
let(:project) { build(:project) }
before do
allow(project).to receive(:default_branch).and_return('master')
end
it 'memoizes and returns the latest successful pipeline for the default branch' do
pipeline = double(:pipeline)
2019-10-12 21:52:04 +05:30
expect(project.ci_pipelines).to receive(:latest_successful_for_ref)
2018-03-17 18:26:18 +05:30
.with(project.default_branch)
.and_return(pipeline)
.once
2.times do
expect(project.latest_successful_pipeline_for_default_branch)
.to eq(pipeline)
end
end
end
describe '#after_import' do
2018-11-08 19:23:39 +05:30
let(:project) { create(:project) }
2019-02-15 15:39:39 +05:30
let(:import_state) { create(:import_state, project: project) }
2018-03-17 18:26:18 +05:30
it 'runs the correct hooks' do
2020-04-08 14:13:33 +05:30
expect(project.repository).to receive(:expire_content_cache)
expect(project.wiki.repository).to receive(:expire_content_cache)
2019-02-15 15:39:39 +05:30
expect(import_state).to receive(:finish)
2018-03-17 18:26:18 +05:30
expect(project).to receive(:update_project_counter_caches)
expect(project).to receive(:after_create_default_branch)
2018-05-09 12:01:36 +05:30
expect(project).to receive(:refresh_markdown_cache!)
2019-03-02 22:35:43 +05:30
expect(InternalId).to receive(:flush_records!).with(project: project)
2020-04-08 14:13:33 +05:30
expect(DetectRepositoryLanguagesWorker).to receive(:perform_async).with(project.id)
2020-07-28 23:09:34 +05:30
expect(project).to receive(:write_repository_config)
2018-03-17 18:26:18 +05:30
project.after_import
end
context 'branch protection' do
let(:project) { create(:project, :repository) }
2019-02-15 15:39:39 +05:30
before do
create(:import_state, :started, project: project)
end
2018-03-17 18:26:18 +05:30
it 'does not protect when branch protection is disabled' do
2020-04-08 14:13:33 +05:30
expect(project.namespace).to receive(:default_branch_protection).and_return(Gitlab::Access::PROTECTION_NONE)
2018-03-17 18:26:18 +05:30
project.after_import
expect(project.protected_branches).to be_empty
end
it "gives developer access to push when branch protection is set to 'developers can push'" do
2020-04-08 14:13:33 +05:30
expect(project.namespace).to receive(:default_branch_protection).and_return(Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
2018-03-17 18:26:18 +05:30
project.after_import
expect(project.protected_branches).not_to be_empty
expect(project.default_branch).to eq(project.protected_branches.first.name)
expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::DEVELOPER])
end
it "gives developer access to merge when branch protection is set to 'developers can merge'" do
2020-04-08 14:13:33 +05:30
expect(project.namespace).to receive(:default_branch_protection).and_return(Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
2018-03-17 18:26:18 +05:30
project.after_import
expect(project.protected_branches).not_to be_empty
expect(project.default_branch).to eq(project.protected_branches.first.name)
expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::DEVELOPER])
end
it 'protects default branch' do
project.after_import
expect(project.protected_branches).not_to be_empty
expect(project.default_branch).to eq(project.protected_branches.first.name)
2018-11-18 11:00:15 +05:30
expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MAINTAINER])
expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::MAINTAINER])
2018-03-17 18:26:18 +05:30
end
end
end
describe '#update_project_counter_caches' do
let(:project) { create(:project) }
it 'updates all project counter caches' do
expect_any_instance_of(Projects::OpenIssuesCountService)
.to receive(:refresh_cache)
.and_call_original
expect_any_instance_of(Projects::OpenMergeRequestsCountService)
.to receive(:refresh_cache)
.and_call_original
project.update_project_counter_caches
end
end
describe '#write_repository_config' do
2020-03-13 15:44:24 +05:30
let_it_be(:project) { create(:project, :repository) }
2018-03-17 18:26:18 +05:30
it 'writes full path in .git/config when key is missing' do
project.write_repository_config
2018-11-08 19:23:39 +05:30
expect(rugged_config['gitlab.fullpath']).to eq project.full_path
2018-03-17 18:26:18 +05:30
end
it 'updates full path in .git/config when key is present' do
project.write_repository_config(gl_full_path: 'old/path')
2018-11-08 19:23:39 +05:30
expect { project.write_repository_config }.to change { rugged_config['gitlab.fullpath'] }.from('old/path').to(project.full_path)
2018-03-17 18:26:18 +05:30
end
it 'does not raise an error with an empty repository' do
project = create(:project_empty_repo)
expect { project.write_repository_config }.not_to raise_error
end
end
2020-07-28 23:09:34 +05:30
describe "#default_branch" do
context "with an empty repository" do
let_it_be(:project) { create(:project_empty_repo) }
context "Gitlab::CurrentSettings.default_branch_name is unavailable" do
before do
expect(Gitlab::CurrentSettings)
.to receive(:default_branch_name)
.and_return(nil)
end
it "returns that value" do
expect(project.default_branch).to be_nil
end
end
context "Gitlab::CurrentSettings.default_branch_name is available" do
before do
expect(Gitlab::CurrentSettings)
.to receive(:default_branch_name)
.and_return('example_branch')
end
it "returns that value" do
expect(project.default_branch).to eq("example_branch")
end
end
end
end
2019-10-31 01:37:42 +05:30
describe '#to_ability_name' do
it 'returns project' do
project = build(:project_empty_repo)
expect(project.to_ability_name).to eq('project')
end
end
2018-03-17 18:26:18 +05:30
describe '#execute_hooks' do
2018-11-20 20:47:30 +05:30
let(:data) { { ref: 'refs/heads/master', data: 'data' } }
2020-03-13 15:44:24 +05:30
2018-11-20 20:47:30 +05:30
it 'executes active projects hooks with the specified scope' do
hook = create(:project_hook, merge_requests_events: false, push_events: true)
expect(ProjectHook).to receive(:select_active)
.with(:push_hooks, data)
.and_return([hook])
project = create(:project, hooks: [hook])
2018-03-17 18:26:18 +05:30
expect_any_instance_of(ProjectHook).to receive(:async_execute).once
2018-11-20 20:47:30 +05:30
project.execute_hooks(data, :push_hooks)
end
it 'does not execute project hooks that dont match the specified scope' do
hook = create(:project_hook, merge_requests_events: true, push_events: false)
project = create(:project, hooks: [hook])
expect_any_instance_of(ProjectHook).not_to receive(:async_execute).once
project.execute_hooks(data, :push_hooks)
end
it 'does not execute project hooks which are not active' do
hook = create(:project_hook, push_events: true)
expect(ProjectHook).to receive(:select_active)
.with(:push_hooks, data)
.and_return([])
project = create(:project, hooks: [hook])
expect_any_instance_of(ProjectHook).not_to receive(:async_execute).once
project.execute_hooks(data, :push_hooks)
2018-03-17 18:26:18 +05:30
end
it 'executes the system hooks with the specified scope' do
2018-11-20 20:47:30 +05:30
expect_any_instance_of(SystemHooksService).to receive(:execute_hooks).with(data, :merge_request_hooks)
2018-03-17 18:26:18 +05:30
project = build(:project)
2018-11-20 20:47:30 +05:30
project.execute_hooks(data, :merge_request_hooks)
2018-03-17 18:26:18 +05:30
end
it 'executes the system hooks when inside a transaction' do
allow_any_instance_of(WebHookService).to receive(:execute)
create(:system_hook, merge_requests_events: true)
project = build(:project)
# Ideally, we'd test that `WebHookWorker.jobs.size` increased by 1,
# but since the entire spec run takes place in a transaction, we never
# actually get to the `after_commit` hook that queues these jobs.
expect do
project.transaction do
2018-11-20 20:47:30 +05:30
project.execute_hooks(data, :merge_request_hooks)
2018-03-17 18:26:18 +05:30
end
end.not_to raise_error # Sidekiq::Worker::EnqueueFromTransactionError
end
end
2018-03-27 19:54:05 +05:30
2020-06-23 00:09:42 +05:30
describe '#execute_services' do
let(:service) { create(:slack_service, push_events: true, merge_requests_events: false, active: true) }
it 'executes services with the specified scope' do
data = 'any data'
expect(SlackService).to receive(:allocate).and_wrap_original do |method|
method.call.tap do |instance|
expect(instance).to receive(:async_execute).with(data).once
end
end
service.project.execute_services(data, :push_hooks)
end
it 'does not execute services that don\'t match the specified scope' do
expect(SlackService).not_to receive(:allocate).and_wrap_original do |method|
method.call.tap do |instance|
expect(instance).not_to receive(:async_execute)
end
end
service.project.execute_services(anything, :merge_request_hooks)
end
end
2019-10-12 21:52:04 +05:30
describe '#has_active_hooks?' do
2020-03-13 15:44:24 +05:30
let_it_be(:project) { create(:project) }
2019-10-12 21:52:04 +05:30
it { expect(project.has_active_hooks?).to be_falsey }
it 'returns true when a matching push hook exists' do
create(:project_hook, push_events: true, project: project)
expect(project.has_active_hooks?(:merge_request_events)).to be_falsey
expect(project.has_active_hooks?).to be_truthy
end
it 'returns true when a matching system hook exists' do
create(:system_hook, push_events: true)
expect(project.has_active_hooks?(:merge_request_events)).to be_falsey
expect(project.has_active_hooks?).to be_truthy
2020-01-12 00:16:45 +05:30
end
it 'returns true when a plugin exists' do
2020-03-13 15:44:24 +05:30
expect(Gitlab::FileHook).to receive(:any?).twice.and_return(true)
2020-01-12 00:16:45 +05:30
expect(project.has_active_hooks?(:merge_request_events)).to be_truthy
expect(project.has_active_hooks?).to be_truthy
2019-10-12 21:52:04 +05:30
end
end
describe '#has_active_services?' do
2020-03-13 15:44:24 +05:30
let_it_be(:project) { create(:project) }
2019-10-12 21:52:04 +05:30
it { expect(project.has_active_services?).to be_falsey }
it 'returns true when a matching service exists' do
create(:custom_issue_tracker_service, push_events: true, merge_requests_events: false, project: project)
expect(project.has_active_services?(:merge_request_hooks)).to be_falsey
expect(project.has_active_services?).to be_truthy
end
end
2018-03-27 19:54:05 +05:30
describe '#badges' do
let(:project_group) { create(:group) }
2019-03-02 22:35:43 +05:30
let(:project) { create(:project, path: 'avatar', namespace: project_group) }
2018-03-27 19:54:05 +05:30
before do
create_list(:project_badge, 2, project: project)
create(:group_badge, group: project_group)
end
it 'returns the project and the project group badges' do
create(:group_badge, group: create(:group))
expect(Badge.count).to eq 4
expect(project.badges.count).to eq 3
end
2019-10-12 21:52:04 +05:30
context 'with nested_groups' do
let(:parent_group) { create(:group) }
2018-03-27 19:54:05 +05:30
2019-10-12 21:52:04 +05:30
before do
create_list(:group_badge, 2, group: project_group)
project_group.update(parent: parent_group)
end
2018-03-27 19:54:05 +05:30
2019-10-12 21:52:04 +05:30
it 'returns the project and the project nested groups badges' do
expect(project.badges.count).to eq 5
2018-03-27 19:54:05 +05:30
end
end
end
2020-03-07 23:17:34 +05:30
context 'with cross internal project merge requests' do
let(:project) { create(:project, :repository, :internal) }
let(:forked_project) { fork_project(project, nil, repository: true) }
let(:user) { double(:user) }
it "does not endlessly loop for internal projects with MRs to each other", :sidekiq_inline do
allow(user).to receive(:can?).and_return(true, false, true)
allow(user).to receive(:id).and_return(1)
create(
:merge_request,
target_project: project,
target_branch: 'merge-test',
source_project: forked_project,
source_branch: 'merge-test',
allow_collaboration: true
)
create(
:merge_request,
target_project: forked_project,
target_branch: 'merge-test',
source_project: project,
source_branch: 'merge-test',
allow_collaboration: true
)
expect(user).to receive(:can?).at_most(5).times
project.branch_allows_collaboration?(user, "merge-test")
end
end
2018-03-27 19:54:05 +05:30
context 'with cross project merge requests' do
let(:user) { create(:user) }
let(:target_project) { create(:project, :repository) }
let(:project) { fork_project(target_project, nil, repository: true) }
2019-02-15 15:39:39 +05:30
let!(:local_merge_request) do
create(
:merge_request,
target_project: project,
target_branch: 'target-branch',
source_project: project,
source_branch: 'awesome-feature-1',
allow_collaboration: true
)
end
2020-10-24 23:57:45 +05:30
2018-03-27 19:54:05 +05:30
let!(:merge_request) do
create(
:merge_request,
target_project: target_project,
target_branch: 'target-branch',
source_project: project,
source_branch: 'awesome-feature-1',
2018-11-08 19:23:39 +05:30
allow_collaboration: true
2018-03-27 19:54:05 +05:30
)
end
before do
target_project.add_developer(user)
end
describe '#merge_requests_allowing_push_to_user' do
it 'returns open merge requests for which the user has developer access to the target project' do
expect(project.merge_requests_allowing_push_to_user(user)).to include(merge_request)
end
it 'does not include closed merge requests' do
merge_request.close
expect(project.merge_requests_allowing_push_to_user(user)).to be_empty
end
it 'does not include merge requests for guest users' do
guest = create(:user)
target_project.add_guest(guest)
expect(project.merge_requests_allowing_push_to_user(guest)).to be_empty
end
it 'does not include the merge request for other users' do
other_user = create(:user)
expect(project.merge_requests_allowing_push_to_user(other_user)).to be_empty
end
it 'is empty when no user is passed' do
expect(project.merge_requests_allowing_push_to_user(nil)).to be_empty
end
end
2019-02-15 15:39:39 +05:30
describe '#any_branch_allows_collaboration?' do
2019-12-26 22:10:19 +05:30
it 'allows access when there are merge requests open allowing collaboration', :sidekiq_might_not_need_inline do
2019-02-15 15:39:39 +05:30
expect(project.any_branch_allows_collaboration?(user))
2018-11-08 19:23:39 +05:30
.to be_truthy
end
2019-02-15 15:39:39 +05:30
it 'does not allow access when there are no merge requests open allowing collaboration' do
merge_request.close!
expect(project.any_branch_allows_collaboration?(user))
.to be_falsey
end
end
describe '#branch_allows_collaboration?' do
2019-12-26 22:10:19 +05:30
it 'allows access if the user can merge the merge request', :sidekiq_might_not_need_inline do
2019-02-15 15:39:39 +05:30
expect(project.branch_allows_collaboration?(user, 'awesome-feature-1'))
2018-03-27 19:54:05 +05:30
.to be_truthy
end
it 'does not allow guest users access' do
guest = create(:user)
target_project.add_guest(guest)
2018-11-08 19:23:39 +05:30
expect(project.branch_allows_collaboration?(guest, 'awesome-feature-1'))
2018-03-27 19:54:05 +05:30
.to be_falsy
end
it 'does not allow access to branches for which the merge request was closed' do
create(:merge_request, :closed,
target_project: target_project,
target_branch: 'target-branch',
source_project: project,
source_branch: 'rejected-feature-1',
2018-11-08 19:23:39 +05:30
allow_collaboration: true)
2018-03-27 19:54:05 +05:30
2018-11-08 19:23:39 +05:30
expect(project.branch_allows_collaboration?(user, 'rejected-feature-1'))
2018-03-27 19:54:05 +05:30
.to be_falsy
end
it 'does not allow access if the user cannot merge the merge request' do
2018-11-18 11:00:15 +05:30
create(:protected_branch, :maintainers_can_push, project: target_project, name: 'target-branch')
2018-03-27 19:54:05 +05:30
2018-11-08 19:23:39 +05:30
expect(project.branch_allows_collaboration?(user, 'awesome-feature-1'))
2018-03-27 19:54:05 +05:30
.to be_falsy
end
context 'when the requeststore is active', :request_store do
it 'only queries per project across instances' do
2018-11-08 19:23:39 +05:30
control = ActiveRecord::QueryRecorder.new { project.branch_allows_collaboration?(user, 'awesome-feature-1') }
2018-03-27 19:54:05 +05:30
2018-11-08 19:23:39 +05:30
expect { 2.times { described_class.find(project.id).branch_allows_collaboration?(user, 'awesome-feature-1') } }
2018-03-27 19:54:05 +05:30
.not_to exceed_query_limit(control).with_threshold(2)
end
end
end
end
2018-05-09 12:01:36 +05:30
2019-07-07 11:18:12 +05:30
describe '#external_authorization_classification_label' do
it 'falls back to the default when none is configured' do
enable_external_authorization_service_check
expect(build(:project).external_authorization_classification_label)
.to eq('default_label')
end
it 'returns the classification label if it was configured on the project' do
enable_external_authorization_service_check
project = build(:project,
external_authorization_classification_label: 'hello')
expect(project.external_authorization_classification_label)
.to eq('hello')
end
end
2018-05-09 12:01:36 +05:30
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
2018-10-15 14:42:47 +05:30
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]) }
2020-03-13 15:44:24 +05:30
2018-10-15 14:42:47 +05:30
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
2018-11-08 19:23:39 +05:30
context 'with uploads' do
2019-02-15 15:39:39 +05:30
it_behaves_like 'model with uploads', true do
2018-11-08 19:23:39 +05:30
let(:model_object) { create(:project, :with_avatar) }
let(:upload_attribute) { :avatar }
let(:uploader_class) { AttachmentUploader }
end
end
2020-03-13 15:44:24 +05:30
describe '#members_among' do
2018-12-05 23:21:45 +05:30
let(:users) { create_list(:user, 3) }
2020-03-13 15:44:24 +05:30
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, namespace: group) }
2018-12-05 23:21:45 +05:30
before do
project.add_guest(users.first)
project.group.add_maintainer(users.last)
end
context 'when users is an Array' do
it 'returns project members among the users' do
expect(project.members_among(users)).to eq([users.first, users.last])
end
it 'maintains input order' do
expect(project.members_among(users.reverse)).to eq([users.last, users.first])
end
it 'returns empty array if users is empty' do
result = project.members_among([])
expect(result).to be_empty
end
end
context 'when users is a relation' do
it 'returns project members among the users' do
result = project.members_among(User.where(id: users.map(&:id)))
expect(result).to be_a(ActiveRecord::Relation)
expect(result).to eq([users.first, users.last])
end
it 'returns empty relation if users is empty' do
result = project.members_among(User.none)
expect(result).to be_a(ActiveRecord::Relation)
expect(result).to be_empty
end
end
end
2020-06-23 00:09:42 +05:30
describe '#find_or_initialize_services' do
2018-12-05 23:21:45 +05:30
it 'returns only enabled services' do
2020-06-23 00:09:42 +05:30
allow(Service).to receive(:available_services_names).and_return(%w[prometheus pushover teamcity])
allow(subject).to receive(:disabled_services).and_return(%w[prometheus])
2018-12-05 23:21:45 +05:30
services = subject.find_or_initialize_services
2020-06-23 00:09:42 +05:30
expect(services.count).to eq(2)
expect(services.map(&:title)).to eq(['JetBrains TeamCity CI', 'Pushover'])
2018-12-05 23:21:45 +05:30
end
end
2020-06-23 00:09:42 +05:30
describe '#find_or_initialize_service' do
2018-12-05 23:21:45 +05:30
it 'avoids N+1 database queries' do
2020-06-23 00:09:42 +05:30
allow(Service).to receive(:available_services_names).and_return(%w[prometheus pushover])
2018-12-05 23:21:45 +05:30
control_count = ActiveRecord::QueryRecorder.new { subject.find_or_initialize_service('prometheus') }.count
allow(Service).to receive(:available_services_names).and_call_original
expect { subject.find_or_initialize_service('prometheus') }.not_to exceed_query_limit(control_count)
2018-11-08 19:23:39 +05:30
end
2018-12-05 23:21:45 +05:30
2020-06-23 00:09:42 +05:30
it 'returns nil if integration is disabled' do
allow(subject).to receive(:disabled_services).and_return(%w[prometheus])
2018-12-05 23:21:45 +05:30
expect(subject.find_or_initialize_service('prometheus')).to be_nil
end
2020-06-23 00:09:42 +05:30
context 'with an existing integration' do
subject { create(:project) }
before do
create(:prometheus_service, project: subject, api_url: 'https://prometheus.project.com/')
end
it 'retrieves the integration' do
expect(subject.find_or_initialize_service('prometheus').api_url).to eq('https://prometheus.project.com/')
end
end
context 'with an instance-level and template integrations' do
before do
create(:prometheus_service, :instance, api_url: 'https://prometheus.instance.com/')
create(:prometheus_service, :template, api_url: 'https://prometheus.template.com/')
end
it 'builds the service from the instance if exists' do
expect(subject.find_or_initialize_service('prometheus').api_url).to eq('https://prometheus.instance.com/')
end
end
context 'with an instance-level and template integrations' do
before do
create(:prometheus_service, :template, api_url: 'https://prometheus.template.com/')
end
it 'builds the service from the template if instance does not exists' do
expect(subject.find_or_initialize_service('prometheus').api_url).to eq('https://prometheus.template.com/')
end
end
context 'without an exisiting integration, nor instance-level or template' do
it 'builds the service if instance or template does not exists' do
expect(subject.find_or_initialize_service('prometheus')).to be_a(PrometheusService)
expect(subject.find_or_initialize_service('prometheus').api_url).to be_nil
end
end
2018-12-05 23:21:45 +05:30
end
2018-12-13 13:39:08 +05:30
describe '.for_group' do
it 'returns the projects for a given group' do
group = create(:group)
project = create(:project, namespace: group)
expect(described_class.for_group(group)).to eq([project])
end
end
2020-10-24 23:57:45 +05:30
describe '.for_repository_storage' do
it 'returns the projects for a given repository storage' do
stub_storage_settings('test_second_storage' => {
'path' => TestEnv::SECOND_STORAGE_PATH,
'gitaly_address' => Gitlab.config.repositories.storages.default.gitaly_address
})
expected_project = create(:project, repository_storage: 'default')
create(:project, repository_storage: 'test_second_storage')
expect(described_class.for_repository_storage('default')).to eq([expected_project])
end
end
describe '.excluding_repository_storage' do
it 'returns the projects excluding the given repository storage' do
stub_storage_settings('test_second_storage' => {
'path' => TestEnv::SECOND_STORAGE_PATH,
'gitaly_address' => Gitlab.config.repositories.storages.default.gitaly_address
})
expected_project = create(:project, repository_storage: 'test_second_storage')
create(:project, repository_storage: 'default')
expect(described_class.excluding_repository_storage('default')).to eq([expected_project])
end
end
2018-12-13 13:39:08 +05:30
describe '.deployments' do
subject { project.deployments }
2020-03-13 15:44:24 +05:30
let(:project) { create(:project, :repository) }
2018-12-13 13:39:08 +05:30
before do
allow_any_instance_of(Deployment).to receive(:create_ref)
end
context 'when there is a deployment record with created status' do
let(:deployment) { create(:deployment, :created, project: project) }
it 'does not return the record' do
is_expected.to be_empty
end
end
context 'when there is a deployment record with running status' do
let(:deployment) { create(:deployment, :running, project: project) }
it 'does not return the record' do
is_expected.to be_empty
end
end
context 'when there is a deployment record with success status' do
let(:deployment) { create(:deployment, :success, project: project) }
it 'returns the record' do
is_expected.to eq([deployment])
end
end
end
describe '#snippets_visible?' do
it 'returns true when a logged in user can read snippets' do
project = create(:project, :public)
user = create(:user)
expect(project.snippets_visible?(user)).to eq(true)
end
it 'returns true when an anonymous user can read snippets' do
project = create(:project, :public)
expect(project.snippets_visible?).to eq(true)
end
it 'returns false when a user can not read snippets' do
project = create(:project, :private)
user = create(:user)
expect(project.snippets_visible?(user)).to eq(false)
end
end
2019-02-15 15:39:39 +05:30
describe '#all_clusters' do
let(:project) { create(:project) }
let(:cluster) { create(:cluster, cluster_type: :project_type, projects: [project]) }
subject { project.all_clusters }
it 'returns project level cluster' do
expect(subject).to eq([cluster])
end
context 'project belongs to a group' do
let(:group_cluster) { create(:cluster, :group) }
let(:group) { group_cluster.group }
let(:project) { create(:project, group: group) }
it 'returns clusters for groups of this project' do
expect(subject).to contain_exactly(cluster, group_cluster)
end
end
2020-01-01 13:55:28 +05:30
context 'project is hosted on instance with integrated cluster' do
let(:group_cluster) { create(:cluster, :group) }
let(:instance_cluster) { create(:cluster, :instance) }
let(:group) { group_cluster.group }
let(:project) { create(:project, group: group) }
it 'returns all available clusters for this project' do
expect(subject).to contain_exactly(cluster, group_cluster, instance_cluster)
end
end
2019-02-15 15:39:39 +05:30
end
describe '#object_pool_params' do
let(:project) { create(:project, :repository, :public) }
subject { project.object_pool_params }
context 'when the objects cannot be pooled' do
let(:project) { create(:project, :repository, :private) }
it { is_expected.to be_empty }
end
context 'when a pool is created' do
it 'returns that pool repository' do
expect(subject).not_to be_empty
expect(subject[:pool_repository]).to be_persisted
2019-07-31 22:56:46 +05:30
expect(project.reload.pool_repository).to eq(subject[:pool_repository])
2019-02-15 15:39:39 +05:30
end
end
end
describe '#git_objects_poolable?' do
subject { project }
2019-12-21 20:55:43 +05:30
2019-12-04 20:38:33 +05:30
context 'when not using hashed storage' do
let(:project) { create(:project, :legacy_storage, :public, :repository) }
2019-02-15 15:39:39 +05:30
it { is_expected.not_to be_git_objects_poolable }
end
2020-01-01 13:55:28 +05:30
context 'when the project is private' do
2019-12-04 20:38:33 +05:30
let(:project) { create(:project, :private) }
2019-02-15 15:39:39 +05:30
2019-12-04 20:38:33 +05:30
it { is_expected.not_to be_git_objects_poolable }
end
2019-02-15 15:39:39 +05:30
2020-01-01 13:55:28 +05:30
context 'when the project is public' do
let(:project) { create(:project, :repository, :public) }
it { is_expected.to be_git_objects_poolable }
end
context 'when the project is internal' do
let(:project) { create(:project, :repository, :internal) }
it { is_expected.to be_git_objects_poolable }
end
2019-12-04 20:38:33 +05:30
context 'when objects are poolable' do
let(:project) { create(:project, :repository, :public) }
2019-02-15 15:39:39 +05:30
2019-12-04 20:38:33 +05:30
it { is_expected.to be_git_objects_poolable }
2019-02-15 15:39:39 +05:30
end
end
2019-03-02 22:35:43 +05:30
describe '#leave_pool_repository' do
let(:pool) { create(:pool_repository) }
let(:project) { create(:project, :repository, pool_repository: pool) }
it 'removes the membership' do
project.leave_pool_repository
expect(pool.member_projects.reload).not_to include(project)
end
end
describe '#check_personal_projects_limit' do
context 'when creating a project for a group' do
it 'does nothing' do
creator = build(:user)
project = build(:project, namespace: build(:group), creator: creator)
allow(creator)
.to receive(:can_create_project?)
.and_return(false)
project.check_personal_projects_limit
expect(project.errors).to be_empty
end
end
context 'when the user is not allowed to create a personal project' do
let(:user) { build(:user) }
let(:project) { build(:project, creator: user) }
before do
allow(user)
.to receive(:can_create_project?)
.and_return(false)
end
context 'when the project limit is zero' do
it 'adds a validation error' do
allow(user)
.to receive(:projects_limit)
.and_return(0)
project.check_personal_projects_limit
expect(project.errors[:limit_reached].first)
.to match(/Personal project creation is not allowed/)
end
end
context 'when the project limit is greater than zero' do
it 'adds a validation error' do
allow(user)
.to receive(:projects_limit)
.and_return(5)
project.check_personal_projects_limit
expect(project.errors[:limit_reached].first)
.to match(/Your project limit is 5 projects/)
end
end
end
context 'when the user is allowed to create personal projects' do
it 'does nothing' do
user = build(:user)
project = build(:project, creator: user)
allow(user)
.to receive(:can_create_project?)
.and_return(true)
project.check_personal_projects_limit
expect(project.errors).to be_empty
end
end
end
2019-12-21 20:55:43 +05:30
context 'pages deployed' do
let(:project) { create(:project) }
{
mark_pages_as_deployed: true,
mark_pages_as_not_deployed: false
}.each do |method_name, flag|
describe method_name do
it "creates new record and sets deployed to #{flag} if none exists yet" do
project.pages_metadatum.destroy!
project.reload
project.send(method_name)
expect(project.pages_metadatum.reload.deployed).to eq(flag)
end
it "updates the existing record and sets deployed to #{flag}" do
pages_metadatum = project.pages_metadatum
pages_metadatum.update!(deployed: !flag)
expect { project.send(method_name) }.to change {
pages_metadatum.reload.deployed
}.from(!flag).to(flag)
end
end
end
end
2019-07-07 11:18:12 +05:30
describe '#has_pool_repsitory?' do
it 'returns false when it does not have a pool repository' do
subject = create(:project, :repository)
expect(subject.has_pool_repository?).to be false
end
it 'returns true when it has a pool repository' do
pool = create(:pool_repository, :ready)
subject = create(:project, :repository, pool_repository: pool)
expect(subject.has_pool_repository?).to be true
end
end
2019-12-04 20:38:33 +05:30
describe '#access_request_approvers_to_be_notified' do
it 'returns a maximum of ten, active, non_requested maintainers of the project in recent_sign_in descending order' do
group = create(:group, :public)
project = create(:project, group: group)
users = create_list(:user, 12, :with_sign_ins)
active_maintainers = users.map do |user|
create(:project_member, :maintainer, user: user)
end
create(:project_member, :maintainer, :blocked, project: project)
create(:project_member, :developer, project: project)
create(:project_member, :access_request, :maintainer, project: project)
active_maintainers_in_recent_sign_in_desc_order = project.members_and_requesters.where(id: active_maintainers).order_recent_sign_in.limit(10)
expect(project.access_request_approvers_to_be_notified).to eq(active_maintainers_in_recent_sign_in_desc_order)
end
end
describe '#pages_lookup_path' do
let(:pages_domain) { build(:pages_domain) }
let(:project) { build(:project) }
it 'returns instance of Pages::LookupPath' do
2019-12-21 20:55:43 +05:30
expect(Pages::LookupPath).to receive(:new).with(project, domain: pages_domain, trim_prefix: 'mygroup').and_call_original
expect(project.pages_lookup_path(domain: pages_domain, trim_prefix: 'mygroup')).to be_a(Pages::LookupPath)
end
end
describe '.with_pages_deployed' do
it 'returns only projects that have pages deployed' do
_project_without_pages = create(:project)
project_with_pages = create(:project)
project_with_pages.mark_pages_as_deployed
expect(described_class.with_pages_deployed).to contain_exactly(project_with_pages)
end
end
describe '.pages_metadata_not_migrated' do
it 'returns only projects that have pages deployed' do
_project_with_pages_metadata_migrated = create(:project)
project_with_pages_metadata_not_migrated = create(:project)
project_with_pages_metadata_not_migrated.pages_metadatum.destroy!
expect(described_class.pages_metadata_not_migrated).to contain_exactly(project_with_pages_metadata_not_migrated)
end
end
describe '#pages_group_root?' do
it 'returns returns true if pages_url is same as pages_group_url' do
project = build(:project)
expect(project).to receive(:pages_url).and_return(project.pages_group_url)
expect(project.pages_group_root?).to eq(true)
end
it 'returns returns false if pages_url is different than pages_group_url' do
project = build(:project)
expect(project.pages_group_root?).to eq(false)
end
end
describe '#closest_setting' do
using RSpec::Parameterized::TableSyntax
shared_examples_for 'fetching closest setting' do
let!(:namespace) { create(:namespace) }
let!(:project) { create(:project, namespace: namespace) }
let(:setting_name) { :some_setting }
let(:setting) { project.closest_setting(setting_name) }
2019-12-04 20:38:33 +05:30
2019-12-21 20:55:43 +05:30
before do
allow(project).to receive(:read_attribute).with(setting_name).and_return(project_setting)
allow(namespace).to receive(:closest_setting).with(setting_name).and_return(group_setting)
allow(Gitlab::CurrentSettings).to receive(setting_name).and_return(global_setting)
end
it 'returns closest non-nil value' do
expect(setting).to eq(result)
end
end
context 'when setting is of non-boolean type' do
where(:global_setting, :group_setting, :project_setting, :result) do
100 | 200 | 300 | 300
100 | 200 | nil | 200
100 | nil | nil | 100
nil | nil | nil | nil
end
with_them do
it_behaves_like 'fetching closest setting'
end
end
context 'when setting is of boolean type' do
where(:global_setting, :group_setting, :project_setting, :result) do
true | true | false | false
true | false | nil | false
true | nil | nil | true
end
with_them do
it_behaves_like 'fetching closest setting'
end
end
end
describe '#drop_visibility_level!' do
context 'when has a group' do
let(:group) { create(:group, visibility_level: group_visibility_level) }
let(:project) { build(:project, namespace: group, visibility_level: project_visibility_level) }
context 'when the group `visibility_level` is more strict' do
let(:group_visibility_level) { Gitlab::VisibilityLevel::PRIVATE }
let(:project_visibility_level) { Gitlab::VisibilityLevel::INTERNAL }
it 'sets `visibility_level` value from the group' do
expect { project.drop_visibility_level! }
.to change { project.visibility_level }
.to(Gitlab::VisibilityLevel::PRIVATE)
end
end
context 'when the group `visibility_level` is less strict' do
let(:group_visibility_level) { Gitlab::VisibilityLevel::INTERNAL }
let(:project_visibility_level) { Gitlab::VisibilityLevel::PRIVATE }
it 'does not change the value of the `visibility_level` field' do
expect { project.drop_visibility_level! }
.not_to change { project.visibility_level }
end
end
end
context 'when `restricted_visibility_levels` of the GitLab instance exist' do
before do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::INTERNAL])
end
let(:project) { build(:project, visibility_level: project_visibility_level) }
context 'when `visibility_level` is included into `restricted_visibility_levels`' do
let(:project_visibility_level) { Gitlab::VisibilityLevel::INTERNAL }
it 'sets `visibility_level` value to `PRIVATE`' do
expect { project.drop_visibility_level! }
.to change { project.visibility_level }
.to(Gitlab::VisibilityLevel::PRIVATE)
end
end
context 'when `restricted_visibility_levels` does not include `visibility_level`' do
let(:project_visibility_level) { Gitlab::VisibilityLevel::PUBLIC }
it 'does not change the value of the `visibility_level` field' do
expect { project.drop_visibility_level! }
.to not_change { project.visibility_level }
end
end
2019-12-04 20:38:33 +05:30
end
end
2020-04-22 19:07:51 +05:30
describe 'with services and chat names' do
subject { create(:project) }
let(:service) { create(:service, project: subject) }
before do
create_list(:chat_name, 5, service: service)
end
it 'removes chat names on removal' do
expect { subject.destroy }.to change { ChatName.count }.by(-5)
end
end
2020-03-13 15:44:24 +05:30
describe 'with_issues_or_mrs_available_for_user' do
before do
Project.delete_all
end
it 'returns correct projects' do
user = create(:user)
project1 = create(:project, :public, :merge_requests_disabled, :issues_enabled)
project2 = create(:project, :public, :merge_requests_disabled, :issues_disabled)
project3 = create(:project, :public, :issues_enabled, :merge_requests_enabled)
project4 = create(:project, :private, :issues_private, :merge_requests_private)
[project1, project2, project3, project4].each { |project| project.add_developer(user) }
expect(described_class.with_issues_or_mrs_available_for_user(user))
.to contain_exactly(project1, project3, project4)
end
end
describe '#limited_protected_branches' do
let(:project) { create(:project) }
let!(:protected_branch) { create(:protected_branch, project: project) }
let!(:another_protected_branch) { create(:protected_branch, project: project) }
subject { project.limited_protected_branches(1) }
it 'returns limited number of protected branches based on specified limit' do
2020-04-22 19:07:51 +05:30
expect(subject.count).to eq(1)
2020-03-13 15:44:24 +05:30
end
end
2020-04-08 14:13:33 +05:30
describe '#all_lfs_objects_oids' do
let(:project) { create(:project) }
let(:lfs_object) { create(:lfs_object) }
let(:another_lfs_object) { create(:lfs_object) }
subject { project.all_lfs_objects_oids }
context 'when project has associated LFS objects' do
before do
create(:lfs_objects_project, lfs_object: lfs_object, project: project)
create(:lfs_objects_project, lfs_object: another_lfs_object, project: project)
end
it 'returns OIDs of LFS objects' do
expect(subject).to match_array([lfs_object.oid, another_lfs_object.oid])
end
context 'and there are specified oids' do
subject { project.all_lfs_objects_oids(oids: [lfs_object.oid]) }
it 'returns OIDs of LFS objects that match specified oids' do
expect(subject).to eq([lfs_object.oid])
end
end
end
context 'when fork has associated LFS objects to itself and source' do
let(:source) { create(:project) }
let(:project) { fork_project(source) }
before do
create(:lfs_objects_project, lfs_object: lfs_object, project: source)
create(:lfs_objects_project, lfs_object: another_lfs_object, project: project)
end
it 'returns OIDs of LFS objects' do
expect(subject).to match_array([lfs_object.oid, another_lfs_object.oid])
end
end
context 'when project has no associated LFS objects' do
it 'returns empty array' do
expect(subject).to be_empty
end
end
end
2020-03-13 15:44:24 +05:30
describe '#lfs_objects_oids' do
let(:project) { create(:project) }
let(:lfs_object) { create(:lfs_object) }
let(:another_lfs_object) { create(:lfs_object) }
subject { project.lfs_objects_oids }
context 'when project has associated LFS objects' do
before do
create(:lfs_objects_project, lfs_object: lfs_object, project: project)
create(:lfs_objects_project, lfs_object: another_lfs_object, project: project)
end
it 'returns OIDs of LFS objects' do
expect(subject).to match_array([lfs_object.oid, another_lfs_object.oid])
end
2020-04-08 14:13:33 +05:30
context 'and there are specified oids' do
subject { project.lfs_objects_oids(oids: [lfs_object.oid]) }
it 'returns OIDs of LFS objects that match specified oids' do
expect(subject).to eq([lfs_object.oid])
end
end
2020-03-13 15:44:24 +05:30
end
context 'when project has no associated LFS objects' do
it 'returns empty array' do
expect(subject).to be_empty
end
end
end
describe '#alerts_service_activated?' do
let!(:project) { create(:project) }
subject { project.alerts_service_activated? }
context 'when project has an activated alerts service' do
before do
create(:alerts_service, project: project)
end
it { is_expected.to be_truthy }
end
context 'when project has an inactive alerts service' do
before do
create(:alerts_service, :inactive, project: project)
end
it { is_expected.to be_falsey }
end
end
2020-07-28 23:09:34 +05:30
describe '#prometheus_service_active?' do
let(:project) { create(:project) }
subject { project.prometheus_service_active? }
before do
create(:prometheus_service, project: project, manual_configuration: manual_configuration)
end
context 'when project has an activated prometheus service' do
let(:manual_configuration) { true }
it { is_expected.to be_truthy }
end
context 'when project has an inactive prometheus service' do
let(:manual_configuration) { false }
it 'the service is marked as inactive' do
expect(subject).to be_falsey
end
end
end
2020-03-13 15:44:24 +05:30
describe '#self_monitoring?' do
let_it_be(:project) { create(:project) }
subject { project.self_monitoring? }
context 'when the project is instance self monitoring' do
before do
stub_application_setting(self_monitoring_project_id: project.id)
end
it { is_expected.to be true }
end
context 'when the project is not self monitoring' do
it { is_expected.to be false }
end
end
2020-04-08 14:13:33 +05:30
describe '#add_export_job' do
context 'if not already present' do
it 'starts project export job' do
user = create(:user)
project = build(:project)
expect(ProjectExportWorker).to receive(:perform_async).with(user.id, project.id, nil, {})
project.add_export_job(current_user: user)
end
end
end
describe '#export_in_progress?' do
let(:project) { build(:project) }
let!(:project_export_job ) { create(:project_export_job, project: project) }
context 'when project export is enqueued' do
it { expect(project.export_in_progress?).to be false }
end
context 'when project export is in progress' do
before do
project_export_job.start!
end
it { expect(project.export_in_progress?).to be true }
end
context 'when project export is completed' do
before do
finish_job(project_export_job)
end
it { expect(project.export_in_progress?).to be false }
end
end
describe '#export_status' do
let(:project) { build(:project) }
let!(:project_export_job ) { create(:project_export_job, project: project) }
context 'when project export is enqueued' do
it { expect(project.export_status).to eq :queued }
end
context 'when project export is in progress' do
before do
project_export_job.start!
end
it { expect(project.export_status).to eq :started }
end
context 'when project export is completed' do
before do
finish_job(project_export_job)
allow(project).to receive(:export_file).and_return(double(ImportExportUploader, file: 'exists.zip'))
end
it { expect(project.export_status).to eq :finished }
end
context 'when project export is being regenerated' do
let!(:new_project_export_job ) { create(:project_export_job, project: project) }
before do
finish_job(project_export_job)
allow(project).to receive(:export_file).and_return(double(ImportExportUploader, file: 'exists.zip'))
end
it { expect(project.export_status).to eq :regeneration_in_progress }
end
end
2020-10-24 23:57:45 +05:30
describe '#has_packages?' do
let(:project) { create(:project, :public) }
subject { project.has_packages?(package_type) }
shared_examples 'has_package' do
context 'package of package_type exists' do
let!(:package) { create("#{package_type}_package", project: project) }
it { is_expected.to be true }
end
context 'package of package_type does not exist' do
it { is_expected.to be false }
end
end
context 'with maven packages' do
it_behaves_like 'has_package' do
let(:package_type) { :maven }
end
end
context 'with npm packages' do
it_behaves_like 'has_package' do
let(:package_type) { :npm }
end
end
context 'with conan packages' do
it_behaves_like 'has_package' do
let(:package_type) { :conan }
end
end
context 'calling has_package? with nil' do
let(:package_type) { nil }
it { is_expected.to be false }
end
end
2020-04-22 19:07:51 +05:30
describe '#environments_for_scope' do
let_it_be(:project, reload: true) { create(:project) }
before do
create_list(:environment, 2, project: project)
end
it 'retrieves all project environments when using the * wildcard' do
expect(project.environments_for_scope("*")).to eq(project.environments)
end
it 'retrieves a specific project environment when using the name of that environment' do
environment = project.environments.first
expect(project.environments_for_scope(environment.name)).to eq([environment])
end
end
describe '#latest_jira_import' do
let_it_be(:project) { create(:project) }
context 'when no jira imports' do
it 'returns nil' do
expect(project.latest_jira_import).to be nil
end
end
context 'when single jira import' do
let!(:jira_import1) { create(:jira_import_state, project: project) }
it 'returns the jira import' do
expect(project.latest_jira_import).to eq(jira_import1)
end
end
context 'when multiple jira imports' do
let!(:jira_import1) { create(:jira_import_state, :finished, created_at: 1.day.ago, project: project) }
let!(:jira_import2) { create(:jira_import_state, :failed, created_at: 2.days.ago, project: project) }
let!(:jira_import3) { create(:jira_import_state, :started, created_at: 3.days.ago, project: project) }
it 'returns latest jira import by created_at' do
expect(project.jira_imports.pluck(:id)).to eq([jira_import3.id, jira_import2.id, jira_import1.id])
expect(project.latest_jira_import).to eq(jira_import1)
end
end
end
2020-07-28 23:09:34 +05:30
describe '#packages_enabled' do
subject { create(:project).packages_enabled }
it { is_expected.to be true }
end
describe '#package_already_taken?' do
let(:namespace) { create(:namespace) }
let(:project) { create(:project, :public, namespace: namespace) }
let!(:package) { create(:npm_package, project: project, name: "@#{namespace.path}/foo") }
context 'no package exists with the same name' do
it 'returns false' do
result = project.package_already_taken?("@#{namespace.path}/bar")
expect(result).to be false
end
it 'returns false if it is the project that the package belongs to' do
result = project.package_already_taken?("@#{namespace.path}/foo")
expect(result).to be false
end
end
context 'a package already exists with the same name' do
let(:alt_project) { create(:project, :public, namespace: namespace) }
it 'returns true' do
result = alt_project.package_already_taken?("@#{namespace.path}/foo")
expect(result).to be true
end
end
end
2020-05-24 23:13:21 +05:30
describe '#design_management_enabled?' do
let(:project) { build(:project) }
where(:lfs_enabled, :hashed_storage_enabled, :expectation) do
false | false | false
true | false | false
false | true | false
true | true | true
end
with_them do
before do
expect(project).to receive(:lfs_enabled?).and_return(lfs_enabled)
allow(project).to receive(:hashed_storage?).with(:repository).and_return(hashed_storage_enabled)
end
it do
expect(project.design_management_enabled?).to be(expectation)
end
end
end
describe '#bots' do
subject { project.bots }
let_it_be(:project) { create(:project) }
let_it_be(:project_bot) { create(:user, :project_bot) }
let_it_be(:user) { create(:user) }
before_all do
[project_bot, user].each do |member|
project.add_maintainer(member)
end
end
it { is_expected.to contain_exactly(project_bot) }
it { is_expected.not_to include(user) }
end
2020-06-23 00:09:42 +05:30
describe "#metrics_setting" do
let(:project) { build(:project) }
it 'creates setting if it does not exist' do
expect(project.metrics_setting).to be_an_instance_of(ProjectMetricsSetting)
end
end
2020-04-08 14:13:33 +05:30
def finish_job(export_job)
export_job.start
export_job.finish
end
2018-12-05 23:21:45 +05:30
def rugged_config
rugged_repo(project.repository).config
2018-11-08 19:23:39 +05:30
end
2019-03-02 22:35:43 +05:30
def create_pipeline(project, status = 'success')
create(:ci_pipeline, project: project,
sha: project.commit.sha,
ref: project.default_branch,
status: status)
end
def create_build(new_pipeline = pipeline, name = 'test')
create(:ci_build, :success, :artifacts,
pipeline: new_pipeline,
status: new_pipeline.status,
name: name)
end
2014-09-02 18:07:02 +05:30
end