diff options
Diffstat (limited to 'spec/models/project_spec.rb')
-rw-r--r-- | spec/models/project_spec.rb | 353 |
1 files changed, 215 insertions, 138 deletions
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index dfc8919e19d..15e5db5af60 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -14,6 +14,8 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do it_behaves_like 'having unique enum values' + it_behaves_like 'ensures runners_token is prefixed', :project + describe 'associations' do it { is_expected.to belong_to(:group) } it { is_expected.to belong_to(:namespace) } @@ -50,6 +52,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do it { is_expected.to have_one(:packagist_integration) } it { is_expected.to have_one(:pushover_integration) } it { is_expected.to have_one(:apple_app_store_integration) } + it { is_expected.to have_one(:google_play_integration) } it { is_expected.to have_one(:asana_integration) } it { is_expected.to have_many(:boards) } it { is_expected.to have_one(:campfire_integration) } @@ -88,6 +91,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do it { is_expected.to have_one(:alerting_setting).class_name('Alerting::ProjectAlertingSetting') } it { is_expected.to have_one(:mock_ci_integration) } it { is_expected.to have_one(:mock_monitoring_integration) } + it { is_expected.to have_one(:service_desk_custom_email_verification).class_name('ServiceDesk::CustomEmailVerification') } it { is_expected.to have_many(:commit_statuses) } it { is_expected.to have_many(:ci_pipelines) } it { is_expected.to have_many(:ci_refs) } @@ -135,6 +139,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do it { is_expected.to have_many(:reviews).inverse_of(:project) } it { is_expected.to have_many(:packages).class_name('Packages::Package') } it { is_expected.to have_many(:package_files).class_name('Packages::PackageFile') } + it { is_expected.to have_many(:rpm_repository_files).class_name('Packages::Rpm::RepositoryFile').inverse_of(:project).dependent(:destroy) } it { is_expected.to have_many(:debian_distributions).class_name('Packages::Debian::ProjectDistribution').dependent(:destroy) } it { is_expected.to have_one(:packages_cleanup_policy).class_name('Packages::Cleanup::Policy').inverse_of(:project) } it { is_expected.to have_many(:pipeline_artifacts).dependent(:restrict_with_error) } @@ -939,6 +944,17 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do end end + describe '#commit_notes' do + let_it_be(:project) { create(:project) } + + it "returns project's commit notes" do + note_1 = create(:note_on_commit, project: project, commit_id: 'commit_id_1') + note_2 = create(:note_on_commit, project: project, commit_id: 'commit_id_2') + + expect(project.commit_notes).to match_array([note_1, note_2]) + end + end + describe '#personal_namespace_holder?' do let_it_be(:group) { create(:group) } let_it_be(:namespace_user) { create(:user) } @@ -1151,7 +1167,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do end describe '#ci_inbound_job_token_scope_enabled?' do - it_behaves_like 'a ci_cd_settings predicate method', prefix: 'ci_' do + it_behaves_like 'a ci_cd_settings predicate method', prefix: 'ci_', default: true do let(:delegated_method) { :inbound_job_token_scope_enabled? } end end @@ -1380,6 +1396,60 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do end end + describe '#to_reference_base' do + using RSpec::Parameterized::TableSyntax + + let_it_be(:user) { create(:user) } + let_it_be(:user_namespace) { user.namespace } + + let_it_be(:parent) { create(:group) } + let_it_be(:group) { create(:group, parent: parent) } + let_it_be(:another_group) { create(:group) } + + let_it_be(:project1) { create(:project, namespace: group) } + let_it_be(:project_namespace) { project1.project_namespace } + + # different project same group + let_it_be(:project2) { create(:project, namespace: group) } + let_it_be(:project_namespace2) { project2.project_namespace } + + # different project from different group + let_it_be(:project3) { create(:project) } + let_it_be(:project_namespace3) { project3.project_namespace } + + # testing references with namespace being: group, project namespace and user namespace + where(:project, :full, :from, :result) do + ref(:project1) | false | nil | nil + ref(:project1) | true | nil | lazy { project.full_path } + ref(:project1) | false | ref(:group) | lazy { project.path } + ref(:project1) | true | ref(:group) | lazy { project.full_path } + ref(:project1) | false | ref(:parent) | lazy { project.full_path } + ref(:project1) | true | ref(:parent) | lazy { project.full_path } + ref(:project1) | false | ref(:project1) | nil + ref(:project1) | true | ref(:project1) | lazy { project.full_path } + ref(:project1) | false | ref(:project_namespace) | nil + ref(:project1) | true | ref(:project_namespace) | lazy { project.full_path } + ref(:project1) | false | ref(:project2) | lazy { project.path } + ref(:project1) | true | ref(:project2) | lazy { project.full_path } + ref(:project1) | false | ref(:project_namespace2) | lazy { project.path } + ref(:project1) | true | ref(:project_namespace2) | lazy { project.full_path } + ref(:project1) | false | ref(:another_group) | lazy { project.full_path } + ref(:project1) | true | ref(:another_group) | lazy { project.full_path } + ref(:project1) | false | ref(:project3) | lazy { project.full_path } + ref(:project1) | true | ref(:project3) | lazy { project.full_path } + ref(:project1) | false | ref(:project_namespace3) | lazy { project.full_path } + ref(:project1) | true | ref(:project_namespace3) | lazy { project.full_path } + ref(:project1) | false | ref(:user_namespace) | lazy { project.full_path } + ref(:project1) | true | ref(:user_namespace) | lazy { project.full_path } + end + + with_them do + it 'returns correct path' do + expect(project.to_reference_base(from, full: full)).to eq(result) + end + end + end + describe '#merge_method' do where(:ff, :rebase, :method) do true | true | :ff @@ -2666,7 +2736,11 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do end describe '#pages_url', feature_category: :pages do + let(:group_name) { 'group' } + let(:project_name) { 'project' } + let(:group) { create(:group, name: group_name) } + let(:nested_group) { create(:group, parent: group) } let(:project_path) { project_name.downcase } let(:project) do @@ -2689,101 +2763,114 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do .and_return(['http://example.com', port].compact.join(':')) end - context 'group page' do - let(:group_name) { 'Group' } - let(:project_name) { 'group.example.com' } + context 'when pages_unique_domain feature flag is disabled' do + before do + stub_feature_flags(pages_unique_domain: false) + end - it { is_expected.to eq("http://group.example.com") } + it { is_expected.to eq('http://group.example.com/project') } + end - context 'mixed case path' do - let(:project_path) { 'Group.example.com' } + context 'when pages_unique_domain feature flag is enabled' do + before do + stub_feature_flags(pages_unique_domain: true) - it { is_expected.to eq("http://group.example.com") } + project.project_setting.update!( + pages_unique_domain_enabled: pages_unique_domain_enabled, + pages_unique_domain: 'unique-domain' + ) end - end - context 'project page' do - let(:group_name) { 'Group' } - let(:project_name) { 'Project' } + context 'when pages_unique_domain_enabled is false' do + let(:pages_unique_domain_enabled) { false } - it { is_expected.to eq("http://group.example.com/project") } + it { is_expected.to eq('http://group.example.com/project') } + end - context 'mixed case path' do - let(:project_path) { 'Project' } + context 'when pages_unique_domain_enabled is false' do + let(:pages_unique_domain_enabled) { true } - it { is_expected.to eq("http://group.example.com/Project") } + it { is_expected.to eq('http://unique-domain.example.com') } end end - context 'when there is an explicit port' do - let(:port) { 3000 } - - context 'when not in dev mode' do - before do - stub_rails_env('production') - end + context 'with nested group' do + let(:project) { create(:project, namespace: nested_group, name: project_name) } + let(:expected_url) { "http://group.example.com/#{nested_group.path}/#{project.path}" } - context 'group page' do - let(:group_name) { 'Group' } - let(:project_name) { 'group.example.com' } + context 'group page' do + let(:project_name) { 'group.example.com' } - it { is_expected.to eq('http://group.example.com:3000/group.example.com') } + it { is_expected.to eq(expected_url) } + end - context 'mixed case path' do - let(:project_path) { 'Group.example.com' } + context 'project page' do + let(:project_name) { 'Project' } - it { is_expected.to eq('http://group.example.com:3000/Group.example.com') } - end - end + it { is_expected.to eq(expected_url) } + end + end - context 'project page' do - let(:group_name) { 'Group' } - let(:project_name) { 'Project' } + context 'when the project matches its namespace url' do + let(:project_name) { 'group.example.com' } - it { is_expected.to eq("http://group.example.com:3000/project") } + it { is_expected.to eq('http://group.example.com') } - context 'mixed case path' do - let(:project_path) { 'Project' } + context 'with different group name capitalization' do + let(:group_name) { 'Group' } - it { is_expected.to eq("http://group.example.com:3000/Project") } - end - end + it { is_expected.to eq("http://group.example.com") } end - context 'when in dev mode' do - before do - stub_rails_env('development') - end - - context 'group page' do - let(:group_name) { 'Group' } - let(:project_name) { 'group.example.com' } + context 'with different project path capitalization' do + let(:project_path) { 'Group.example.com' } - it { is_expected.to eq('http://group.example.com:3000') } + it { is_expected.to eq("http://group.example.com") } + end - context 'mixed case path' do - let(:project_path) { 'Group.example.com' } + context 'with different project name capitalization' do + let(:project_name) { 'Project' } - it { is_expected.to eq('http://group.example.com:3000') } - end - end + it { is_expected.to eq("http://group.example.com/project") } + end - context 'project page' do - let(:group_name) { 'Group' } - let(:project_name) { 'Project' } + context 'when there is an explicit port' do + let(:port) { 3000 } - it { is_expected.to eq("http://group.example.com:3000/project") } + context 'when not in dev mode' do + before do + stub_rails_env('production') + end - context 'mixed case path' do - let(:project_path) { 'Project' } + it { is_expected.to eq('http://group.example.com:3000/group.example.com') } + end - it { is_expected.to eq("http://group.example.com:3000/Project") } + context 'when in dev mode' do + before do + stub_rails_env('development') end + + it { is_expected.to eq('http://group.example.com:3000') } end end end end + describe '#pages_unique_url', feature_category: :pages do + let(:project_settings) { create(:project_setting, pages_unique_domain: 'unique-domain') } + let(:project) { build(:project, project_setting: project_settings) } + let(:domain) { 'example.com' } + + before do + allow(Settings.pages).to receive(:host).and_return(domain) + allow(Gitlab.config.pages).to receive(:url).and_return("http://#{domain}") + end + + it 'returns the pages unique url' do + expect(project.pages_unique_url).to eq('http://unique-domain.example.com') + end + end + describe '#pages_namespace_url', feature_category: :pages do let(:group) { create(:group, name: group_name) } let(:project) { create(:project, namespace: group, name: project_name) } @@ -3565,6 +3652,44 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do end end + describe '#beautified_import_status_name' do + context 'when import not finished' do + it 'returns the right beautified import status' do + project = create(:project, :import_started) + + expect(project.beautified_import_status_name).to eq('started') + end + end + + context 'when import is finished' do + context 'when import is partially completed' do + it 'returns partially completed' do + project = create(:project) + + create(:import_state, project: project, status: 'finished', checksums: { + 'fetched' => { 'labels' => 10 }, + 'imported' => { 'labels' => 9 } + }) + + expect(project.beautified_import_status_name).to eq('partially completed') + end + end + + context 'when import is fully completed' do + it 'returns completed' do + project = create(:project) + + create(:import_state, project: project, status: 'finished', checksums: { + 'fetched' => { 'labels' => 10 }, + 'imported' => { 'labels' => 10 } + }) + + expect(project.beautified_import_status_name).to eq('completed') + end + end + end + end + describe '#add_import_job' do let(:import_jid) { '123' } @@ -3843,21 +3968,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do end describe '#ancestors' do - context 'with linear_project_ancestors feature flag enabled' do - before do - stub_feature_flags(linear_project_ancestors: true) - end - - include_examples '#ancestors' - end - - context 'with linear_project_ancestors feature flag disabled' do - before do - stub_feature_flags(linear_project_ancestors: false) - end - - include_examples '#ancestors' - end + include_examples '#ancestors' end describe '#ancestors_upto' do @@ -4643,52 +4754,6 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do end end - describe '#pages_url' do - let(:group) { create(:group, name: 'Group') } - let(:nested_group) { create(:group, parent: group) } - 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 - let(:project) { create(:project, namespace: group, name: project_name) } - - 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 - let(:project) { create(:project, namespace: nested_group, name: project_name) } - let(:expected_url) { "http://group.example.com/#{nested_group.path}/#{project.path}" } - - context 'group page' do - 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 - describe '#lfs_http_url_to_repo' do let(:project) { create(:project) } @@ -6049,7 +6114,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do it 'executes hooks which were backed off and are no longer backed off' do project = create(:project) hook = create(:project_hook, project: project, push_events: true) - WebHook::FAILURE_THRESHOLD.succ.times { hook.backoff! } + WebHooks::AutoDisabling::FAILURE_THRESHOLD.succ.times { hook.backoff! } expect_any_instance_of(ProjectHook).to receive(:async_execute).once @@ -7305,20 +7370,6 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do end end - describe 'with integrations and chat names' do - subject { create(:project) } - - let(:integration) { create(:integration, project: subject) } - - before do - create_list(:chat_name, 5, integration: integration) - end - - it 'does not remove chat names on removal' do - expect { subject.destroy! }.not_to change { ChatName.count } - end - end - describe 'with_issues_or_mrs_available_for_user' do before do Project.delete_all @@ -8842,6 +8893,32 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do end end + describe 'deprecated project attributes' do + where(:project_attr, :project_method, :project_feature_attr) do + :wiki_enabled | :wiki_enabled? | :wiki_access_level + :builds_enabled | :builds_enabled? | :builds_access_level + :merge_requests_enabled | :merge_requests_enabled? | :merge_requests_access_level + :issues_enabled | :issues_enabled? | :issues_access_level + :snippets_enabled | :snippets_enabled? | :snippets_access_level + end + + with_them do + it 'delegates the attributes to project feature' do + project = Project.new(project_attr => false) + + expect(project.public_send(project_method)).to eq(false) + expect(project.project_feature.public_send(project_feature_attr)).to eq(ProjectFeature::DISABLED) + end + + it 'sets the default value' do + project = Project.new + + expect(project.public_send(project_method)).to eq(true) + expect(project.project_feature.public_send(project_feature_attr)).to eq(ProjectFeature::ENABLED) + end + end + end + private def finish_job(export_job) |