Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models/project_spec.rb')
-rw-r--r--spec/models/project_spec.rb230
1 files changed, 180 insertions, 50 deletions
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 12c17e699e3..c57c2792f87 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe Project, factory_default: :keep do
it { is_expected.to belong_to(:creator).class_name('User') }
it { is_expected.to belong_to(:pool_repository) }
it { is_expected.to have_many(:users) }
- it { is_expected.to have_many(:services) }
+ it { is_expected.to have_many(:integrations) }
it { is_expected.to have_many(:events) }
it { is_expected.to have_many(:merge_requests) }
it { is_expected.to have_many(:merge_request_metrics).class_name('MergeRequest::Metrics') }
@@ -46,13 +46,13 @@ RSpec.describe Project, factory_default: :keep do
it { is_expected.to have_one(:asana_service) }
it { is_expected.to have_many(:boards) }
it { is_expected.to have_one(:campfire_service) }
+ it { is_expected.to have_one(:datadog_service) }
it { is_expected.to have_one(:discord_service) }
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) }
@@ -114,7 +114,8 @@ RSpec.describe Project, factory_default: :keep do
it { is_expected.to have_many(:lfs_file_locks) }
it { is_expected.to have_many(:project_deploy_tokens) }
it { is_expected.to have_many(:deploy_tokens).through(:project_deploy_tokens) }
- it { is_expected.to have_many(:cycle_analytics_stages) }
+ it { is_expected.to have_many(:cycle_analytics_stages).inverse_of(:project) }
+ it { is_expected.to have_many(:value_streams).inverse_of(:project) }
it { is_expected.to have_many(:external_pull_requests) }
it { is_expected.to have_many(:sourced_pipelines) }
it { is_expected.to have_many(:source_pipelines) }
@@ -131,6 +132,7 @@ RSpec.describe Project, factory_default: :keep do
it { is_expected.to have_many(:debian_distributions).class_name('Packages::Debian::ProjectDistribution').dependent(:destroy) }
it { is_expected.to have_many(:pipeline_artifacts) }
it { is_expected.to have_many(:terraform_states).class_name('Terraform::State').inverse_of(:project) }
+ it { is_expected.to have_many(:timelogs) }
# GitLab Pages
it { is_expected.to have_many(:pages_domains) }
@@ -215,7 +217,7 @@ RSpec.describe Project, factory_default: :keep do
it 'does not raise an error' do
project = create(:project)
- expect { project.update(ci_cd_settings: nil) }.not_to raise_exception
+ expect { project.update!(ci_cd_settings: nil) }.not_to raise_exception
end
end
@@ -873,13 +875,13 @@ RSpec.describe Project, factory_default: :keep do
end
it 'returns the most recent timestamp' do
- project.update(updated_at: nil,
+ project.update!(updated_at: nil,
last_activity_at: timestamp,
last_repository_updated_at: timestamp - 1.hour)
expect(project.last_activity_date).to be_like_time(timestamp)
- project.update(updated_at: timestamp,
+ project.update!(updated_at: timestamp,
last_activity_at: timestamp - 1.hour,
last_repository_updated_at: nil)
@@ -1076,14 +1078,14 @@ RSpec.describe Project, factory_default: :keep do
it 'returns nil and does not query services when there is no external issue tracker' do
project = create(:project)
- expect(project).not_to receive(:services)
+ expect(project).not_to receive(:integrations)
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
project = create(:redmine_project)
- expect(project).to receive(:services).once.and_call_original
+ expect(project).to receive(:integrations).once.and_call_original
2.times { expect(project.external_issue_tracker).to be_a_kind_of(RedmineService) }
end
end
@@ -1116,7 +1118,7 @@ RSpec.describe Project, factory_default: :keep do
it 'becomes false when external issue tracker service is destroyed' do
expect do
- Service.find(service.id).delete
+ Integration.find(service.id).delete
end.to change { subject }.to(false)
end
@@ -1133,7 +1135,7 @@ RSpec.describe Project, factory_default: :keep do
it 'does not become false when external issue tracker service is destroyed' do
expect do
- Service.find(service.id).delete
+ Integration.find(service.id).delete
end.not_to change { subject }
end
@@ -1191,7 +1193,7 @@ RSpec.describe Project, factory_default: :keep do
it 'becomes false if the external wiki service is destroyed' do
expect do
- Service.find(service.id).delete
+ Integration.find(service.id).delete
end.to change { subject }.to(false)
end
@@ -1277,7 +1279,9 @@ RSpec.describe Project, factory_default: :keep do
it 'is false if avatar is html page' do
project.update_attribute(:avatar, 'uploads/avatar.html')
- 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, webp'])
+ project.avatar_type
+
+ expect(project.errors.added?(:avatar, "file format is not supported. Please try one of the following supported formats: png, jpg, jpeg, gif, bmp, tiff, ico, webp")).to be true
end
end
@@ -2670,7 +2674,7 @@ RSpec.describe Project, factory_default: :keep do
context 'with pending pipeline' do
it 'returns empty relation' do
- pipeline.update(status: 'pending')
+ pipeline.update!(status: 'pending')
pending_build = create_build(pipeline)
expect { project.latest_successful_build_for_ref!(pending_build.name) }
@@ -2813,11 +2817,11 @@ RSpec.describe Project, factory_default: :keep do
end
describe '#remove_import_data' do
- let_it_be(:import_data) { ProjectImportData.new(data: { 'test' => 'some data' }) }
+ let(: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) }
+ let!(:project) { create(:project, import_type: 'jira', import_data: import_data) }
+ let!(:jira_import) { create(:jira_import_state, project: project) }
it 'does remove import data' do
expect(project.mirror?).to be false
@@ -2827,8 +2831,7 @@ RSpec.describe Project, factory_default: :keep do
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) }
+ let!(:project) { create(:project, import_type: 'github', import_data: import_data) }
it 'removes import data' do
expect(project.mirror?).to be false
@@ -2864,7 +2867,7 @@ RSpec.describe Project, factory_default: :keep do
end
it 'returns false when remote mirror is disabled' do
- project.remote_mirrors.first.update(enabled: false)
+ project.remote_mirrors.first.update!(enabled: false)
is_expected.to be_falsy
end
@@ -2895,7 +2898,7 @@ RSpec.describe Project, factory_default: :keep do
end
it 'does not sync disabled remote mirrors' do
- project.remote_mirrors.first.update(enabled: false)
+ project.remote_mirrors.first.update!(enabled: false)
expect_any_instance_of(RemoteMirror).not_to receive(:sync)
@@ -2933,7 +2936,7 @@ RSpec.describe Project, factory_default: :keep do
it 'fails stuck remote mirrors' do
project = create(:project, :repository, :remote_mirror)
- project.remote_mirrors.first.update(
+ project.remote_mirrors.first.update!(
update_status: :started,
last_update_started_at: 2.days.ago
)
@@ -3191,7 +3194,7 @@ RSpec.describe Project, factory_default: :keep do
end
it 'returns the root of the fork network when the directs source was deleted' do
- forked_project.destroy
+ forked_project.destroy!
expect(second_fork.fork_source).to eq(project)
end
@@ -3435,7 +3438,7 @@ RSpec.describe Project, factory_default: :keep do
let(:environment) { 'foo%bar/test' }
it 'matches literally for _' do
- ci_variable.update(environment_scope: 'foo%bar/*')
+ ci_variable.environment_scope = 'foo%bar/*'
is_expected.to contain_exactly(ci_variable)
end
@@ -3676,7 +3679,7 @@ RSpec.describe Project, factory_default: :keep do
it "updates the namespace_id when changed" do
namespace = create(:namespace)
- project.update(namespace: namespace)
+ project.update!(namespace: namespace)
expect(project.statistics.namespace_id).to eq namespace.id
end
@@ -3969,14 +3972,14 @@ RSpec.describe Project, factory_default: :keep 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)
+ 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
- project.update(updated_at: Time.current)
+ project.update!(updated_at: Time.current)
end
end
@@ -4060,7 +4063,7 @@ RSpec.describe Project, factory_default: :keep do
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 )
+ project_4.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE, merge_requests_access_level: ProjectFeature::PRIVATE )
project_ids = described_class.ids_with_issuables_available_for(user).pluck(:id)
@@ -4103,7 +4106,7 @@ RSpec.describe Project, factory_default: :keep 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)
+ project.project_feature.update!(merge_requests_access_level: nil)
is_expected.to include(project)
end
@@ -4391,7 +4394,7 @@ RSpec.describe Project, factory_default: :keep do
it 'is run when the project is destroyed' do
expect(project).to receive(:legacy_remove_pages).and_call_original
- expect { project.destroy }.not_to raise_error
+ expect { project.destroy! }.not_to raise_error
end
end
@@ -4921,7 +4924,7 @@ RSpec.describe Project, factory_default: :keep do
context 'when enabled on group' do
it 'has auto devops implicitly enabled' do
- project.update(namespace: create(:group, :auto_devops_enabled))
+ project.update!(namespace: create(:group, :auto_devops_enabled))
expect(project).to have_auto_devops_implicitly_enabled
end
@@ -4930,7 +4933,7 @@ RSpec.describe Project, factory_default: :keep do
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)
+ project.update!(namespace: subgroup)
expect(project).to have_auto_devops_implicitly_enabled
end
@@ -5404,7 +5407,7 @@ RSpec.describe Project, factory_default: :keep do
before do
create_list(:group_badge, 2, group: project_group)
- project_group.update(parent: parent_group)
+ project_group.update!(parent: parent_group)
end
it 'returns the project and the project nested groups badges' do
@@ -5799,16 +5802,16 @@ RSpec.describe Project, factory_default: :keep do
end
it 'avoids N+1 database queries with more available services' do
- allow(Service).to receive(:available_services_names).and_return(%w[pushover])
+ allow(Integration).to receive(:available_services_names).and_return(%w[pushover])
control_count = ActiveRecord::QueryRecorder.new { subject.find_or_initialize_services }
- allow(Service).to receive(:available_services_names).and_call_original
+ allow(Integration).to receive(:available_services_names).and_call_original
expect { subject.find_or_initialize_services }.not_to exceed_query_limit(control_count)
end
context 'with disabled services' do
before do
- allow(Service).to receive(:available_services_names).and_return(%w[prometheus pushover teamcity])
+ allow(Integration).to receive(:available_services_names).and_return(%w[prometheus pushover teamcity])
allow(subject).to receive(:disabled_services).and_return(%w[prometheus])
end
@@ -5843,11 +5846,11 @@ RSpec.describe Project, factory_default: :keep do
describe '#find_or_initialize_service' do
it 'avoids N+1 database queries' do
- allow(Service).to receive(:available_services_names).and_return(%w[prometheus pushover])
+ allow(Integration).to receive(:available_services_names).and_return(%w[prometheus pushover])
control_count = ActiveRecord::QueryRecorder.new { subject.find_or_initialize_service('prometheus') }.count
- allow(Service).to receive(:available_services_names).and_call_original
+ allow(Integration).to receive(:available_services_names).and_call_original
expect { subject.find_or_initialize_service('prometheus') }.not_to exceed_query_limit(control_count)
end
@@ -6301,23 +6304,31 @@ RSpec.describe Project, factory_default: :keep do
end
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)
+ let_it_be(:project) { create(:project, group: create(:group, :public)) }
+ it 'returns a maximum of ten maintainers of the project in recent_sign_in descending order' do
users = create_list(:user, 12, :with_sign_ins)
active_maintainers = users.map do |user|
- create(:project_member, :maintainer, user: user)
+ create(:project_member, :maintainer, user: user, project: project)
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)
+ active_maintainers_in_recent_sign_in_desc_order = project.members_and_requesters
+ .id_in(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
+
+ it 'returns active, non_invited, non_requested maintainers of the project' do
+ maintainer = create(:project_member, :maintainer, source: project)
+
+ create(:project_member, :developer, project: project)
+ create(:project_member, :maintainer, :invited, project: project)
+ create(:project_member, :maintainer, :access_request, project: project)
+ create(:project_member, :maintainer, :blocked, project: project)
+
+ expect(project.access_request_approvers_to_be_notified.to_a).to eq([maintainer])
+ end
end
describe '#pages_lookup_path' do
@@ -6478,17 +6489,17 @@ RSpec.describe Project, factory_default: :keep do
end
end
- describe 'with services and chat names' do
+ describe 'with integrations and chat names' do
subject { create(:project) }
- let(:service) { create(:service, project: subject) }
+ let(:integration) { create(:service, project: subject) }
before do
- create_list(:chat_name, 5, service: service)
+ create_list(:chat_name, 5, integration: integration)
end
it 'removes chat names on removal' do
- expect { subject.destroy }.to change { ChatName.count }.by(-5)
+ expect { subject.destroy! }.to change { ChatName.count }.by(-5)
end
end
@@ -6823,6 +6834,26 @@ RSpec.describe Project, factory_default: :keep do
end
end
+ describe '#parent_loaded?' do
+ let_it_be(:project) { create(:project) }
+
+ before do
+ project.namespace = create(:namespace)
+
+ project.reload
+ end
+
+ it 'is false when the parent is not loaded' do
+ expect(project.parent_loaded?).to be_falsey
+ end
+
+ it 'is true when the parent is loaded' do
+ project.parent
+
+ expect(project.parent_loaded?).to be_truthy
+ end
+ end
+
describe '#bots' do
subject { project.bots }
@@ -6889,6 +6920,105 @@ RSpec.describe Project, factory_default: :keep do
end
end
end
+
+ describe '#activity_path' do
+ it 'returns the project activity_path' do
+ expected_path = "/#{project.namespace.path}/#{project.name}/activity"
+
+ expect(project.activity_path).to eq(expected_path)
+ end
+ end
+ end
+
+ describe '#default_branch_or_main' do
+ let(:project) { create(:project, :repository) }
+
+ it 'returns default branch' do
+ expect(project.default_branch_or_main).to eq(project.default_branch)
+ end
+
+ context 'when default branch is nil' do
+ let(:project) { create(:project, :empty_repo) }
+
+ it 'returns Gitlab::DefaultBranch.value' do
+ expect(project.default_branch_or_main).to eq(Gitlab::DefaultBranch.value)
+ end
+ end
+ end
+
+ describe '#increment_statistic_value' do
+ let(:project) { build_stubbed(:project) }
+
+ subject(:increment) do
+ project.increment_statistic_value(:build_artifacts_size, -10)
+ end
+
+ it 'increments the value' do
+ expect(ProjectStatistics)
+ .to receive(:increment_statistic)
+ .with(project, :build_artifacts_size, -10)
+
+ increment
+ end
+
+ context 'when the project is scheduled for removal' do
+ let(:project) { build_stubbed(:project, pending_delete: true) }
+
+ it 'does not increment the value' do
+ expect(ProjectStatistics).not_to receive(:increment_statistic)
+
+ increment
+ end
+ end
+ end
+
+ describe 'topics' do
+ let_it_be(:project) { create(:project, tag_list: 'topic1, topic2, topic3') }
+
+ it 'topic_list returns correct string array' do
+ expect(project.topic_list).to match_array(%w[topic1 topic2 topic3])
+ end
+
+ it 'topics returns correct tag records' do
+ expect(project.topics.first.class.name).to eq('ActsAsTaggableOn::Tag')
+ expect(project.topics.map(&:name)).to match_array(%w[topic1 topic2 topic3])
+ end
+
+ context 'aliases' do
+ it 'tag_list returns correct string array' do
+ expect(project.tag_list).to match_array(%w[topic1 topic2 topic3])
+ end
+
+ it 'tags returns correct tag records' do
+ expect(project.tags.first.class.name).to eq('ActsAsTaggableOn::Tag')
+ expect(project.tags.map(&:name)).to match_array(%w[topic1 topic2 topic3])
+ end
+ end
+
+ context 'intermediate state during background migration' do
+ before do
+ project.taggings.first.update!(context: 'tags')
+ project.instance_variable_set("@tag_list", nil)
+ project.reload
+ end
+
+ it 'tag_list returns string array including old and new topics' do
+ expect(project.tag_list).to match_array(%w[topic1 topic2 topic3])
+ end
+
+ it 'tags returns old and new tag records' do
+ expect(project.tags.first.class.name).to eq('ActsAsTaggableOn::Tag')
+ expect(project.tags.map(&:name)).to match_array(%w[topic1 topic2 topic3])
+ expect(project.taggings.map(&:context)).to match_array(%w[tags topics topics])
+ end
+
+ it 'update tag_list adds new topics and removes old topics' do
+ project.update!(tag_list: 'topic1, topic2, topic3, topic4')
+
+ expect(project.tags.map(&:name)).to match_array(%w[topic1 topic2 topic3 topic4])
+ expect(project.taggings.map(&:context)).to match_array(%w[topics topics topics topics])
+ end
+ end
end
def finish_job(export_job)