diff options
Diffstat (limited to 'spec/models/project_spec.rb')
-rw-r--r-- | spec/models/project_spec.rb | 362 |
1 files changed, 299 insertions, 63 deletions
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 7fe48e66def..9f3313e67b5 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -92,6 +92,7 @@ describe Project do it { is_expected.to have_many(:pipeline_schedules) } it { is_expected.to have_many(:members_and_requesters) } it { is_expected.to have_many(:clusters) } + it { is_expected.to have_many(:management_clusters).class_name('Clusters::Cluster') } it { is_expected.to have_many(:kubernetes_namespaces) } it { is_expected.to have_many(:custom_attributes).class_name('ProjectCustomAttribute') } it { is_expected.to have_many(:project_badges).class_name('ProjectBadge') } @@ -100,6 +101,8 @@ describe Project do 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(:external_pull_requests) } + it { is_expected.to have_many(:sourced_pipelines) } + it { is_expected.to have_many(:source_pipelines) } it 'has an inverse relationship with merge requests' do expect(described_class.reflect_on_association(:merge_requests).has_inverse?).to eq(:target_project) @@ -132,6 +135,13 @@ describe Project do expect(project.ci_cd_settings).to be_an_instance_of(ProjectCiCdSetting) expect(project.ci_cd_settings).to be_persisted end + + it 'automatically creates a Pages metadata row' do + project = create(:project) + + expect(project.pages_metadatum).to be_an_instance_of(ProjectPagesMetadatum) + expect(project.pages_metadatum).to be_persisted + end end context 'updating cd_cd_settings' do @@ -143,7 +153,7 @@ describe Project do end describe '#members & #requesters' do - let(:project) { create(:project, :public, :access_requestable) } + let(:project) { create(:project, :public) } let(:requester) { create(:user) } let(:developer) { create(:user) } before do @@ -621,8 +631,38 @@ describe Project do describe "#web_url" do let(:project) { create(:project, path: "somewhere") } - it 'returns the full web URL for this repo' do - expect(project.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.namespace.full_path}/somewhere") + context 'when given the only_path option' do + subject { project.web_url(only_path: only_path) } + + context 'when only_path is false' do + let(:only_path) { false } + + it 'returns the full web URL for this repo' do + expect(subject).to eq("#{Gitlab.config.gitlab.url}/#{project.namespace.full_path}/somewhere") + end + end + + context 'when only_path is true' do + let(:only_path) { true } + + it 'returns the relative web URL for this repo' do + expect(subject).to eq("/#{project.namespace.full_path}/somewhere") + end + end + + context 'when only_path is nil' do + let(:only_path) { nil } + + it 'returns the full web URL for this repo' do + expect(subject).to eq("#{Gitlab.config.gitlab.url}/#{project.namespace.full_path}/somewhere") + end + end + end + + context 'when not given the only_path option' do + it 'returns the full web URL for this repo' do + expect(project.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.namespace.full_path}/somewhere") + end end end @@ -2380,29 +2420,6 @@ describe Project do expect(project.emails_disabled?).to be_truthy end end - - context 'when :emails_disabled feature flag is off' do - before do - stub_feature_flags(emails_disabled: false) - end - - context 'emails disabled in group' do - it 'returns false' do - allow(project.namespace).to receive(:emails_disabled?) { true } - - expect(project.emails_disabled?).to be_falsey - end - end - - context 'emails enabled in group' do - it 'returns false' do - allow(project.namespace).to receive(:emails_disabled?) { false } - project.update_attribute(:emails_disabled, true) - - expect(project.emails_disabled?).to be_falsey - end - end - end end describe '#lfs_enabled?' do @@ -3239,20 +3256,78 @@ describe Project do describe '#http_url_to_repo' do let(:project) { create(:project) } - it 'returns the url to the repo without a username' do - expect(project.http_url_to_repo).to eq("#{project.web_url}.git") - expect(project.http_url_to_repo).not_to include('@') + context 'when a custom HTTP clone URL root is not set' do + it 'returns the url to the repo without a username' do + expect(project.http_url_to_repo).to eq("#{project.web_url}.git") + expect(project.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: custom_http_clone_url_root) + end + + context 'when custom HTTP clone URL root has a relative URL root' do + context 'when custom HTTP clone URL root ends with a slash' do + let(:custom_http_clone_url_root) { 'https://git.example.com:51234/mygitlab/' } + + it 'returns the url to the repo, with the root replaced with the custom one' do + expect(project.http_url_to_repo).to eq("https://git.example.com:51234/mygitlab/#{project.full_path}.git") + end + end + + context 'when custom HTTP clone URL root does not end with a slash' do + let(:custom_http_clone_url_root) { 'https://git.example.com:51234/mygitlab' } + + it 'returns the url to the repo, with the root replaced with the custom one' do + expect(project.http_url_to_repo).to eq("https://git.example.com:51234/mygitlab/#{project.full_path}.git") + end + end + end + + context 'when custom HTTP clone URL root does not have a relative URL root' do + context 'when custom HTTP clone URL root ends with a slash' do + let(:custom_http_clone_url_root) { 'https://git.example.com:51234/' } + + it 'returns the url to the repo, with the root replaced with the custom one' do + expect(project.http_url_to_repo).to eq("https://git.example.com:51234/#{project.full_path}.git") + end + end + + context 'when custom HTTP clone URL root does not end with a slash' do + let(:custom_http_clone_url_root) { 'https://git.example.com:51234' } + + it 'returns the url to the repo, with the root replaced with the custom one' do + expect(project.http_url_to_repo).to eq("https://git.example.com:51234/#{project.full_path}.git") + end + end + end end end describe '#lfs_http_url_to_repo' do let(:project) { create(:project) } - 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') + 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 + + 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("#{project.web_url}.git") - expect(lfs_http_url_to_repo).not_to include('@') + expect(lfs_http_url_to_repo).to eq("https://git.example.com:51234/#{project.full_path}.git") + end end end @@ -3556,7 +3631,8 @@ describe Project do end describe '#remove_pages' do - let(:project) { create(:project) } + let(:project) { create(:project).tap { |project| project.mark_pages_as_deployed } } + let(:pages_metadatum) { project.pages_metadatum } let(:namespace) { project.namespace } let(:pages_path) { project.pages_path } @@ -3569,12 +3645,12 @@ describe Project do end end - it 'removes the pages directory' do + it 'removes the pages directory and marks the project as not having pages deployed' do expect_any_instance_of(Projects::UpdatePagesConfigurationService).to receive(:execute) 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) - project.remove_pages + expect { project.remove_pages }.to change { pages_metadatum.reload.deployed }.from(true).to(false) end it 'is a no-op when there is no namespace' do @@ -3584,13 +3660,13 @@ describe Project do expect_any_instance_of(Projects::UpdatePagesConfigurationService).not_to receive(:execute) expect_any_instance_of(Gitlab::PagesTransfer).not_to receive(:rename_project) - project.remove_pages + expect { project.remove_pages }.not_to change { pages_metadatum.reload.deployed } end it 'is run when the project is destroyed' do expect(project).to receive(:remove_pages).and_call_original - project.destroy + expect { project.destroy }.not_to raise_error end end @@ -3663,14 +3739,6 @@ describe Project do end end - describe '#ensure_storage_path_exists' do - it 'delegates to gitlab_shell to ensure namespace is created' do - expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage, project.base_dir) - - project.ensure_storage_path_exists - end - end - describe '#legacy_storage?' do it 'returns true when storage_version is nil' do project = build(:project, storage_version: nil) @@ -3785,16 +3853,6 @@ describe Project do end end - describe '#ensure_storage_path_exists' do - it 'delegates to gitlab_shell to ensure namespace is created' do - allow(project).to receive(:gitlab_shell).and_return(gitlab_shell) - - expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage, hashed_prefix) - - project.ensure_storage_path_exists - 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)) @@ -4225,13 +4283,24 @@ describe Project do end describe '#check_repository_path_availability' do - let(:project) { build(:project) } + let(:project) { build(:project, :repository, :legacy_storage) } + subject { project.check_repository_path_availability } - it 'skips gitlab-shell exists?' do - project.skip_disk_validation = true + context 'when the repository already exists' do + let(:project) { create(:project, :repository, :legacy_storage) } - expect(project.gitlab_shell).not_to receive(:exists?) - expect(project.check_repository_path_availability).to be_truthy + it { is_expected.to be_falsey } + end + + context 'when the repository does not exist' do + it { is_expected.to be_truthy } + + it 'skips gitlab-shell exists?' do + project.skip_disk_validation = true + + expect(project.gitlab_shell).not_to receive(:repository_exists?) + is_expected.to be_truthy + end end end @@ -4945,6 +5014,7 @@ describe Project do describe '#git_objects_poolable?' do subject { project } + context 'when not using hashed storage' do let(:project) { create(:project, :legacy_storage, :public, :repository) } @@ -5044,6 +5114,35 @@ describe Project do end end + 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 + describe '#has_pool_repsitory?' do it 'returns false when it does not have a pool repository' do subject = create(:project, :repository) @@ -5084,9 +5183,146 @@ describe Project do let(:project) { build(:project) } it 'returns instance of Pages::LookupPath' do - expect(Pages::LookupPath).to receive(:new).with(project, domain: pages_domain).and_call_original + 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) } - expect(project.pages_lookup_path(domain: pages_domain)).to be_a(Pages::LookupPath) + 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 end end |