diff options
Diffstat (limited to 'spec')
45 files changed, 1292 insertions, 193 deletions
diff --git a/spec/db/importers/common_metrics_importer_spec.rb b/spec/db/importers/common_metrics_importer_spec.rb index 68260820958..6133b17ac61 100644 --- a/spec/db/importers/common_metrics_importer_spec.rb +++ b/spec/db/importers/common_metrics_importer_spec.rb @@ -4,12 +4,18 @@ require 'rails_helper' require Rails.root.join("db", "importers", "common_metrics_importer.rb") describe Importers::PrometheusMetric do + let(:existing_group_titles) do + ::PrometheusMetric::GROUP_DETAILS.each_with_object({}) do |(key, value), memo| + memo[key] = value[:group_title] + end + end + it 'group enum equals ::PrometheusMetric' do expect(described_class.groups).to eq(::PrometheusMetric.groups) end it 'GROUP_TITLES equals ::PrometheusMetric' do - expect(described_class::GROUP_TITLES).to eq(::PrometheusMetric::GROUP_TITLES) + expect(described_class::GROUP_TITLES).to eq(existing_group_titles) end end diff --git a/spec/factories/releases.rb b/spec/factories/releases.rb index 18047c74a5d..cab6b4a811f 100644 --- a/spec/factories/releases.rb +++ b/spec/factories/releases.rb @@ -1,8 +1,15 @@ FactoryBot.define do factory :release do tag "v1.1.0" + sha 'b83d6e391c22777fca1ed3012fce84f633d7fed0' name { tag } description "Awesome release" project + author + + trait :legacy do + sha nil + author nil + end end end diff --git a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb index d790bdc82ce..d19408ee87f 100644 --- a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb +++ b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb @@ -90,9 +90,6 @@ describe 'Merge request > User creates image diff notes', :js do %w(inline parallel).each do |view| context "#{view} view" do - let(:merge_request) { create(:merge_request_with_diffs, :with_image_diffs, source_project: project, author: user) } - let(:path) { "files/images/ee_repo_logo.png" } - let(:position) do Gitlab::Diff::Position.new( old_path: path, @@ -108,9 +105,11 @@ describe 'Merge request > User creates image diff notes', :js do let!(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, position: position) } - describe 'creating a new diff note' do + shared_examples 'creates image diff note' do before do visit diffs_project_merge_request_path(project, merge_request, view: view) + wait_for_requests + create_image_diff_note end @@ -132,6 +131,32 @@ describe 'Merge request > User creates image diff notes', :js do expect(page).to have_content('image diff test comment') end end + + context 'when images are not stored in LFS' do + let(:merge_request) { create(:merge_request_with_diffs, :with_image_diffs, source_project: project, author: user) } + let(:path) { 'files/images/ee_repo_logo.png' } + + it_behaves_like 'creates image diff note' + end + + context 'when images are stored in LFS' do + let(:merge_request) { create(:merge_request, source_project: project, target_project: project, source_branch: 'png-lfs', target_branch: 'master', author: user) } + let(:path) { 'files/images/logo-black.png' } + + before do + allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) + project.update_attribute(:lfs_enabled, true) + end + + it 'shows lfs badges' do + visit diffs_project_merge_request_path(project, merge_request, view: view) + wait_for_requests + + expect(page.all('.diff-file span.label-lfs', visible: :all)).not_to be_empty + end + + it_behaves_like 'creates image diff note' + end end end diff --git a/spec/features/merge_request/user_sees_diff_spec.rb b/spec/features/merge_request/user_sees_diff_spec.rb index 0df9e4bbc1a..04b07525919 100644 --- a/spec/features/merge_request/user_sees_diff_spec.rb +++ b/spec/features/merge_request/user_sees_diff_spec.rb @@ -87,20 +87,6 @@ describe 'Merge request > User sees diff', :js do let(:current_user) { project.owner } let(:branch_name) {"test_branch"} - def create_file(branch_name, file_name, content) - Files::CreateService.new( - project, - current_user, - start_branch: branch_name, - branch_name: branch_name, - commit_message: "Create file", - file_path: file_name, - file_content: content - ).execute - - project.commit(branch_name) - end - it 'escapes any HTML special characters in the diff chunk header' do file_content = <<~CONTENT @@ -136,5 +122,61 @@ describe 'Merge request > User sees diff', :js do expect(page).to have_css(".line[lang='rust'] .k") end end + + context 'when file is stored in LFS' do + let(:merge_request) { create(:merge_request, source_project: project) } + let(:current_user) { project.owner } + + context 'when LFS is enabled on the project' do + before do + allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) + project.update_attribute(:lfs_enabled, true) + + create_file('master', file_name, project.repository.blob_at('master', 'files/lfs/lfs_object.iso').data) + + visit diffs_project_merge_request_path(project, merge_request) + end + + context 'when file is an image', :js do + let(:file_name) { 'files/lfs/image.png' } + + it 'shows an error message' do + expect(page).not_to have_content('could not be displayed because it is stored in LFS') + end + end + + context 'when file is not an image' do + let(:file_name) { 'files/lfs/ruby.rb' } + + it 'shows an error message' do + expect(page).to have_content('This source diff could not be displayed because it is stored in LFS') + end + end + end + + context 'when LFS is not enabled' do + before do + visit diffs_project_merge_request_path(project, merge_request) + end + + it 'displays the diff' do + expect(page).to have_content('size 1575078') + end + end + end + + def create_file(branch_name, file_name, content) + Files::CreateService.new( + project, + current_user, + start_branch: branch_name, + branch_name: branch_name, + commit_message: "Create file", + file_path: file_name, + file_content: content + ).execute + + project.commit(branch_name) + end end end diff --git a/spec/features/merge_request/user_sees_versions_spec.rb b/spec/features/merge_request/user_sees_versions_spec.rb index f7512294bef..63d8decc2d2 100644 --- a/spec/features/merge_request/user_sees_versions_spec.rb +++ b/spec/features/merge_request/user_sees_versions_spec.rb @@ -64,6 +64,17 @@ describe 'Merge request > User sees versions', :js do end end + it 'shows the commit SHAs for every version in the dropdown' do + page.within '.mr-version-dropdown' do + find('.btn-default').click + + page.within('.dropdown-content') do + shas = merge_request.merge_request_diffs.map { |diff| Commit.truncate_sha(diff.head_commit_sha) } + shas.each { |sha| expect(page).to have_content(sha) } + end + end + end + it 'shows comments that were last relevant at that version' do expect(page).to have_content '5 changed files' diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb index 5e0434c1c2c..f45bcabd196 100644 --- a/spec/features/profiles/user_edit_profile_spec.rb +++ b/spec/features/profiles/user_edit_profile_spec.rb @@ -147,6 +147,9 @@ describe 'User edit profile' do end context 'user menu' do + let(:issue) { create(:issue, project: project)} + let(:project) { create(:project) } + def open_user_status_modal find('.header-user-dropdown-toggle').click @@ -205,6 +208,17 @@ describe 'User edit profile' do end end + it 'does not update the awards panel emoji' do + project.add_maintainer(user) + visit(project_issue_path(project, issue)) + + emoji = 'biohazard' + open_user_status_modal + select_emoji(emoji, true) + + expect(page.all('.award-control .js-counter')).to all(have_content('0')) + end + it 'adds message to user status' do message = 'I have something to say' open_user_status_modal diff --git a/spec/features/projects/commits/user_browses_commits_spec.rb b/spec/features/projects/commits/user_browses_commits_spec.rb index 2159adf49fc..574a8aefd63 100644 --- a/spec/features/projects/commits/user_browses_commits_spec.rb +++ b/spec/features/projects/commits/user_browses_commits_spec.rb @@ -93,7 +93,7 @@ describe 'User browses commits' do it 'shows a blank label' do allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(nil) - allow_any_instance_of(Gitlab::Diff::File).to receive(:raw_binary?).and_return(true) + allow_any_instance_of(Gitlab::Diff::File).to receive(:binary?).and_return(true) visit(project_commit_path(project, commit)) diff --git a/spec/finders/releases_finder_spec.rb b/spec/finders/releases_finder_spec.rb new file mode 100644 index 00000000000..32ee15134a2 --- /dev/null +++ b/spec/finders/releases_finder_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe ReleasesFinder do + let(:user) { create(:user) } + let(:project) { create(:project, :repository) } + let(:repository) { project.repository } + let(:v1_0_0) { create(:release, project: project, tag: 'v1.0.0') } + let(:v1_1_0) { create(:release, project: project, tag: 'v1.1.0') } + + subject { described_class.new(project, user)} + + before do + v1_0_0.update_attribute(:created_at, 2.days.ago) + v1_1_0.update_attribute(:created_at, 1.day.ago) + end + + describe '#execute' do + context 'when the user is not part of the project' do + it 'returns no releases' do + releases = subject.execute + + expect(releases).to be_empty + end + end + + context 'when the user is a project developer' do + before do + project.add_developer(user) + end + + it 'sorts by creation date' do + releases = subject.execute + + expect(releases).to be_present + expect(releases.size).to eq(2) + expect(releases).to eq([v1_1_0, v1_0_0]) + end + end + end +end diff --git a/spec/fixtures/api/schemas/entities/diff_viewer.json b/spec/fixtures/api/schemas/entities/diff_viewer.json index 19780f49a88..81325cd86c6 100644 --- a/spec/fixtures/api/schemas/entities/diff_viewer.json +++ b/spec/fixtures/api/schemas/entities/diff_viewer.json @@ -1,8 +1,20 @@ { "type": "object", - "required": ["name"], + "required": [ + "name" + ], "properties": { - "name": { "type": ["string"] } + "name": { + "type": [ + "string" + ] + }, + "error": { + "type": [ + "string", + "null" + ] + } }, "additionalProperties": false } diff --git a/spec/fixtures/api/schemas/release.json b/spec/fixtures/api/schemas/release.json new file mode 100644 index 00000000000..844405c3acd --- /dev/null +++ b/spec/fixtures/api/schemas/release.json @@ -0,0 +1,18 @@ +{ + "type": "object", + "required": ["name", "tag_name"], + "properties": { + "name": { "type": "string" }, + "tag_name": { "type": "string" }, + "description": { "type": "string" }, + "description_html": { "type": "string" }, + "created_at": { "type": "date" }, + "commit": { + "oneOf": [{ "type": "null" }, { "$ref": "public_api/v4/commit/basic.json" }] + }, + "author": { + "oneOf": [{ "type": "null" }, { "$ref": "public_api/v4/user/basic.json" }] + } + }, + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/releases.json b/spec/fixtures/api/schemas/releases.json new file mode 100644 index 00000000000..e26215707fe --- /dev/null +++ b/spec/fixtures/api/schemas/releases.json @@ -0,0 +1,4 @@ +{ + "type": "array", + "items": { "$ref": "release.json" } +} diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb index 53c010fa0db..5396243f44d 100644 --- a/spec/helpers/diff_helper_spec.rb +++ b/spec/helpers/diff_helper_spec.rb @@ -256,43 +256,6 @@ describe DiffHelper do end end - context 'viewer related' do - let(:viewer) { diff_file.simple_viewer } - - before do - assign(:project, project) - end - - describe '#diff_render_error_reason' do - context 'for error :too_large' do - before do - expect(viewer).to receive(:render_error).and_return(:too_large) - end - - it 'returns an error message' do - expect(helper.diff_render_error_reason(viewer)).to eq('it is too large') - end - end - - context 'for error :server_side_but_stored_externally' do - before do - expect(viewer).to receive(:render_error).and_return(:server_side_but_stored_externally) - expect(diff_file).to receive(:external_storage).and_return(:lfs) - end - - it 'returns an error message' do - expect(helper.diff_render_error_reason(viewer)).to eq('it is stored in LFS') - end - end - end - - describe '#diff_render_error_options' do - it 'includes a "view the blob" link' do - expect(helper.diff_render_error_options(viewer)).to include(/view the blob/) - end - end - end - context '#diff_file_path_text' do it 'returns full path by default' do expect(diff_file_path_text(diff_file)).to eq(diff_file.new_path) diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb index 58a49124ce6..1c73a936e17 100644 --- a/spec/lib/api/helpers_spec.rb +++ b/spec/lib/api/helpers_spec.rb @@ -148,4 +148,36 @@ describe API::Helpers do it_behaves_like 'user namespace finder' end + + describe '#send_git_blob' do + context 'content disposition' do + let(:repository) { double } + let(:blob) { double(name: 'foobar') } + + let(:send_git_blob) do + subject.send(:send_git_blob, repository, blob) + end + + before do + allow(subject).to receive(:env).and_return({}) + allow(subject).to receive(:content_type) + allow(subject).to receive(:header).and_return({}) + allow(Gitlab::Workhorse).to receive(:send_git_blob) + end + + context 'when blob name is null' do + let(:blob) { double(name: nil) } + + it 'returns only the disposition' do + expect(send_git_blob['Content-Disposition']).to eq 'attachment' + end + end + + context 'when blob name is not null' do + it 'returns disposition with the blob name' do + expect(send_git_blob['Content-Disposition']).to eq 'attachment; filename="foobar"' + end + end + end + end end diff --git a/spec/lib/gitlab/blob_helper_spec.rb b/spec/lib/gitlab/blob_helper_spec.rb index 0b56f8687c3..e057385b35f 100644 --- a/spec/lib/gitlab/blob_helper_spec.rb +++ b/spec/lib/gitlab/blob_helper_spec.rb @@ -53,11 +53,11 @@ describe Gitlab::BlobHelper do describe '#text?' do it 'returns true' do - expect(blob.text?).to be_truthy + expect(blob.text_in_repo?).to be_truthy end it 'returns false' do - expect(large_blob.text?).to be_falsey + expect(large_blob.text_in_repo?).to be_falsey end end diff --git a/spec/lib/gitlab/checks/diff_check_spec.rb b/spec/lib/gitlab/checks/diff_check_spec.rb index eeec1e83179..a341dfa5636 100644 --- a/spec/lib/gitlab/checks/diff_check_spec.rb +++ b/spec/lib/gitlab/checks/diff_check_spec.rb @@ -47,5 +47,43 @@ describe Gitlab::Checks::DiffCheck do end end end + + context 'commit diff validations' do + before do + allow(subject).to receive(:validations_for_diff).and_return([lambda { |diff| return }]) + + expect_any_instance_of(Commit).to receive(:raw_deltas).and_call_original + + subject.validate! + end + + context 'when request store is inactive' do + it 'are run for every commit' do + expect_any_instance_of(Commit).to receive(:raw_deltas).and_call_original + + subject.validate! + end + end + + context 'when request store is active', :request_store do + it 'are cached for every commit' do + expect_any_instance_of(Commit).not_to receive(:raw_deltas) + + subject.validate! + end + + it 'are run for not cached commits' do + allow(project.repository).to receive(:new_commits).and_return( + project.repository.commits_between('be93687618e4b132087f430a4d8fc3a609c9b77c', 'a5391128b0ef5d21df5dd23d98557f4ef12fae20') + ) + change_access.instance_variable_set(:@commits, project.repository.new_commits) + + expect(project.repository.new_commits.first).not_to receive(:raw_deltas).and_call_original + expect(project.repository.new_commits.last).to receive(:raw_deltas).and_call_original + + subject.validate! + end + end + end end end diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index b15d22c634a..862590268ca 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -310,7 +310,7 @@ describe Gitlab::Diff::File do context 'when the content changed' do context 'when the file represented by the diff file is binary' do before do - allow(diff_file).to receive(:raw_binary?).and_return(true) + allow(diff_file).to receive(:binary?).and_return(true) end it 'returns a No Preview viewer' do @@ -345,7 +345,7 @@ describe Gitlab::Diff::File do context 'when the file represented by the diff file is binary' do before do - allow(diff_file).to receive(:raw_binary?).and_return(true) + allow(diff_file).to receive(:binary?).and_return(true) end it 'returns an Added viewer' do @@ -380,7 +380,7 @@ describe Gitlab::Diff::File do context 'when the file represented by the diff file is binary' do before do - allow(diff_file).to receive(:raw_binary?).and_return(true) + allow(diff_file).to receive(:binary?).and_return(true) end it 'returns a Deleted viewer' do @@ -436,7 +436,7 @@ describe Gitlab::Diff::File do allow(diff_file).to receive(:deleted_file?).and_return(false) allow(diff_file).to receive(:renamed_file?).and_return(false) allow(diff_file).to receive(:mode_changed?).and_return(false) - allow(diff_file).to receive(:raw_text?).and_return(false) + allow(diff_file).to receive(:text?).and_return(false) end it 'returns a No Preview viewer' do diff --git a/spec/lib/gitlab/diff/lines_unfolder_spec.rb b/spec/lib/gitlab/diff/lines_unfolder_spec.rb index 8e00c8e0e30..f22c2c90334 100644 --- a/spec/lib/gitlab/diff/lines_unfolder_spec.rb +++ b/spec/lib/gitlab/diff/lines_unfolder_spec.rb @@ -185,7 +185,7 @@ describe Gitlab::Diff::LinesUnfolder do let(:project) { create(:project) } - let(:old_blob) { Gitlab::Git::Blob.new(data: raw_old_blob) } + let(:old_blob) { Blob.decorate(Gitlab::Git::Blob.new(data: raw_old_blob, size: 10)) } let(:diff) do Gitlab::Git::Diff.new(diff: raw_diff, diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb index 80dd3dcc58e..1bcec04d28f 100644 --- a/spec/lib/gitlab/git/blob_spec.rb +++ b/spec/lib/gitlab/git/blob_spec.rb @@ -59,7 +59,7 @@ describe Gitlab::Git::Blob, :seed_helper do it { expect(blob.data[0..10]).to eq("*.rbc\n*.sas") } it { expect(blob.size).to eq(241) } it { expect(blob.mode).to eq("100644") } - it { expect(blob).not_to be_binary } + it { expect(blob).not_to be_binary_in_repo } end context 'file in root with leading slash' do @@ -92,7 +92,7 @@ describe Gitlab::Git::Blob, :seed_helper do end it 'does not mark the blob as binary' do - expect(blob).not_to be_binary + expect(blob).not_to be_binary_in_repo end end @@ -123,7 +123,7 @@ describe Gitlab::Git::Blob, :seed_helper do .with(hash_including(binary: true)) .and_call_original - expect(blob).to be_binary + expect(blob).to be_binary_in_repo end end end @@ -196,7 +196,7 @@ describe Gitlab::Git::Blob, :seed_helper do it { expect(blob.id).to eq('409f37c4f05865e4fb208c771485f211a22c4c2d') } it { expect(blob.data).to eq('') } it 'does not mark the blob as binary' do - expect(blob).not_to be_binary + expect(blob).not_to be_binary_in_repo end end diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index a417ef77c9e..8d8eb50ad76 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -709,10 +709,22 @@ describe Gitlab::GitAccess do project.add_developer(user) end - it 'checks LFS integrity only for first change' do - expect_any_instance_of(Gitlab::Checks::LfsIntegrity).to receive(:objects_missing?).exactly(1).times + context 'when LFS is not enabled' do + it 'does not run LFSIntegrity check' do + expect(Gitlab::Checks::LfsIntegrity).not_to receive(:new) - push_access_check + push_access_check + end + end + + context 'when LFS is enabled' do + it 'checks LFS integrity only for first change' do + allow(project).to receive(:lfs_enabled?).and_return(true) + + expect_any_instance_of(Gitlab::Checks::LfsIntegrity).to receive(:objects_missing?).exactly(1).times + + push_access_check + end end end diff --git a/spec/lib/gitlab/gitaly_client/blobs_stitcher_spec.rb b/spec/lib/gitlab/gitaly_client/blobs_stitcher_spec.rb index 9db710e759e..742b2872c40 100644 --- a/spec/lib/gitlab/gitaly_client/blobs_stitcher_spec.rb +++ b/spec/lib/gitlab/gitaly_client/blobs_stitcher_spec.rb @@ -21,7 +21,7 @@ describe Gitlab::GitalyClient::BlobsStitcher do expect(blobs[0].size).to eq(1642) expect(blobs[0].commit_id).to eq('f00ba7') expect(blobs[0].data).to eq("first-line\nsecond-line") - expect(blobs[0].binary?).to be false + expect(blobs[0].binary_in_repo?).to be false expect(blobs[1].id).to eq('abcdef2') expect(blobs[1].mode).to eq('100644') @@ -30,7 +30,7 @@ describe Gitlab::GitalyClient::BlobsStitcher do expect(blobs[1].size).to eq(2461) expect(blobs[1].commit_id).to eq('f00ba8') expect(blobs[1].data).to eq("GIF87a\x90\x01".b) - expect(blobs[1].binary?).to be true + expect(blobs[1].binary_in_repo?).to be true end end end diff --git a/spec/lib/gitlab/legacy_github_import/importer_spec.rb b/spec/lib/gitlab/legacy_github_import/importer_spec.rb index d2df21d7bb5..6bc3792eb22 100644 --- a/spec/lib/gitlab/legacy_github_import/importer_spec.rb +++ b/spec/lib/gitlab/legacy_github_import/importer_spec.rb @@ -138,7 +138,7 @@ describe Gitlab::LegacyGithubImport::Importer do let(:release2) do double( - tag_name: 'v2.0.0', + tag_name: 'v1.1.0', name: 'Second release', body: nil, draft: false, diff --git a/spec/lib/gitlab/prometheus/metric_group_spec.rb b/spec/lib/gitlab/prometheus/metric_group_spec.rb index e7d16e73663..5cc6827488b 100644 --- a/spec/lib/gitlab/prometheus/metric_group_spec.rb +++ b/spec/lib/gitlab/prometheus/metric_group_spec.rb @@ -21,6 +21,13 @@ describe Gitlab::Prometheus::MetricGroup do common_metric_group_a.id, common_metric_group_b_q1.id, common_metric_group_b_q2.id) end + + it 'orders by priority' do + priorities = subject.map(&:priority) + names = subject.map(&:name) + expect(priorities).to eq([10, 5]) + expect(names).to eq(['Response metrics (AWS ELB)', 'System metrics (Kubernetes)']) + end end describe '.for_project' do diff --git a/spec/lib/json_web_token/rsa_token_spec.rb b/spec/lib/json_web_token/rsa_token_spec.rb index d6edc964844..a3c54651e80 100644 --- a/spec/lib/json_web_token/rsa_token_spec.rb +++ b/spec/lib/json_web_token/rsa_token_spec.rb @@ -25,7 +25,7 @@ describe JSONWebToken::RSAToken do rsa_token['key'] = 'value' end - subject { JWT.decode(rsa_encoded, rsa_key) } + subject { JWT.decode(rsa_encoded, rsa_key, true, { algorithm: 'RS256' }) } it { expect {subject}.not_to raise_error } it { expect(subject.first).to include('key' => 'value') } @@ -39,7 +39,7 @@ describe JSONWebToken::RSAToken do context 'for invalid key to raise an exception' do let(:new_key) { OpenSSL::PKey::RSA.generate(512) } - subject { JWT.decode(rsa_encoded, new_key) } + subject { JWT.decode(rsa_encoded, new_key, true, { algorithm: 'RS256' }) } it { expect {subject}.to raise_error(JWT::DecodeError) } end diff --git a/spec/models/blob_spec.rb b/spec/models/blob_spec.rb index e8c03b587e2..05cf242e84d 100644 --- a/spec/models/blob_spec.rb +++ b/spec/models/blob_spec.rb @@ -122,14 +122,14 @@ describe Blob do end end - describe '#raw_binary?' do + describe '#binary?' do context 'if the blob is stored externally' do context 'if the extension has a rich viewer' do context 'if the viewer is binary' do it 'returns true' do blob = fake_blob(path: 'file.pdf', lfs: true) - expect(blob.raw_binary?).to be_truthy + expect(blob.binary?).to be_truthy end end @@ -137,7 +137,7 @@ describe Blob do it 'return false' do blob = fake_blob(path: 'file.md', lfs: true) - expect(blob.raw_binary?).to be_falsey + expect(blob.binary?).to be_falsey end end end @@ -148,7 +148,7 @@ describe Blob do it 'returns false' do blob = fake_blob(path: 'file.txt', lfs: true) - expect(blob.raw_binary?).to be_falsey + expect(blob.binary?).to be_falsey end end @@ -156,7 +156,7 @@ describe Blob do it 'returns false' do blob = fake_blob(path: 'file.ics', lfs: true) - expect(blob.raw_binary?).to be_falsey + expect(blob.binary?).to be_falsey end end end @@ -166,7 +166,7 @@ describe Blob do it 'returns false' do blob = fake_blob(path: 'file.rb', lfs: true) - expect(blob.raw_binary?).to be_falsey + expect(blob.binary?).to be_falsey end end @@ -174,7 +174,7 @@ describe Blob do it 'returns true' do blob = fake_blob(path: 'file.exe', lfs: true) - expect(blob.raw_binary?).to be_truthy + expect(blob.binary?).to be_truthy end end end @@ -184,7 +184,7 @@ describe Blob do it 'returns false' do blob = fake_blob(path: 'file.ini', lfs: true) - expect(blob.raw_binary?).to be_falsey + expect(blob.binary?).to be_falsey end end @@ -192,7 +192,7 @@ describe Blob do it 'returns true' do blob = fake_blob(path: 'file.wtf', lfs: true) - expect(blob.raw_binary?).to be_truthy + expect(blob.binary?).to be_truthy end end end @@ -204,7 +204,7 @@ describe Blob do it 'returns true' do blob = fake_blob(path: 'file.pdf', binary: true) - expect(blob.raw_binary?).to be_truthy + expect(blob.binary?).to be_truthy end end @@ -212,7 +212,7 @@ describe Blob do it 'return false' do blob = fake_blob(path: 'file.md') - expect(blob.raw_binary?).to be_falsey + expect(blob.binary?).to be_falsey end end end diff --git a/spec/models/clusters/applications/cert_manager_spec.rb b/spec/models/clusters/applications/cert_manager_spec.rb index 170c6001eaf..e825f3e2392 100644 --- a/spec/models/clusters/applications/cert_manager_spec.rb +++ b/spec/models/clusters/applications/cert_manager_spec.rb @@ -14,7 +14,7 @@ describe Clusters::Applications::CertManager do let(:application) { create(:clusters_applications_cert_managers, :scheduled, version: 'v0.4.0') } it 'updates the application version' do - expect(application.reload.version).to eq('v0.5.0') + expect(application.reload.version).to eq('v0.5.2') end end end @@ -28,7 +28,7 @@ describe Clusters::Applications::CertManager do it 'should be initialized with cert_manager arguments' do expect(subject.name).to eq('certmanager') expect(subject.chart).to eq('stable/cert-manager') - expect(subject.version).to eq('v0.5.0') + expect(subject.version).to eq('v0.5.2') expect(subject).not_to be_rbac expect(subject.files).to eq(cert_manager.files.merge(cluster_issuer_file)) expect(subject.postinstall).to eq(['/usr/bin/kubectl create -f /data/helm/certmanager/config/cluster_issuer.yaml']) @@ -57,7 +57,7 @@ describe Clusters::Applications::CertManager do let(:cert_manager) { create(:clusters_applications_cert_managers, :errored, version: '0.0.1') } it 'should be initialized with the locked version' do - expect(subject.version).to eq('v0.5.0') + expect(subject.version).to eq('v0.5.2') end end end diff --git a/spec/models/diff_viewer/base_spec.rb b/spec/models/diff_viewer/base_spec.rb index c90b32c5d77..f4efe5a7b3a 100644 --- a/spec/models/diff_viewer/base_spec.rb +++ b/spec/models/diff_viewer/base_spec.rb @@ -58,7 +58,7 @@ describe DiffViewer::Base do context 'when the binaryness does not match' do before do - allow_any_instance_of(Blob).to receive(:binary?).and_return(true) + allow_any_instance_of(Blob).to receive(:binary_in_repo?).and_return(true) end it 'returns false' do @@ -141,4 +141,25 @@ describe DiffViewer::Base do end end end + + describe '#render_error_message' do + it 'returns nothing when no render_error' do + expect(viewer.render_error).to be_nil + expect(viewer.render_error_message).to be_nil + end + + context 'when render_error error' do + before do + allow(viewer).to receive(:render_error).and_return(:too_large) + end + + it 'returns an error message' do + expect(viewer.render_error_message).to include('it is too large') + end + + it 'includes a "view the blob" link' do + expect(viewer.render_error_message).to include('view the blob') + end + end + end end diff --git a/spec/models/diff_viewer/server_side_spec.rb b/spec/models/diff_viewer/server_side_spec.rb index 98a8f6d4cc9..86b14b6ebf3 100644 --- a/spec/models/diff_viewer/server_side_spec.rb +++ b/spec/models/diff_viewer/server_side_spec.rb @@ -32,4 +32,24 @@ describe DiffViewer::ServerSide do end end end + + describe '#render_error_reason' do + context 'when the diff file is stored externally' do + before do + allow(diff_file).to receive(:stored_externally?).and_return(true) + end + + it 'returns error message if stored in LFS' do + allow(diff_file).to receive(:external_storage).and_return(:lfs) + + expect(subject.render_error_message).to include('it is stored in LFS') + end + + it 'returns error message if stored externally' do + allow(diff_file).to receive(:external_storage).and_return(:foo) + + expect(subject.render_error_message).to include('it is stored externally') + end + end + end end diff --git a/spec/models/prometheus_metric_spec.rb b/spec/models/prometheus_metric_spec.rb index 3692fe9a559..2b978c1c8ff 100644 --- a/spec/models/prometheus_metric_spec.rb +++ b/spec/models/prometheus_metric_spec.rb @@ -59,11 +59,65 @@ describe PrometheusMetric do end end + it_behaves_like 'group_title', :nginx_ingress_vts, 'Response metrics (NGINX Ingress VTS)' + it_behaves_like 'group_title', :nginx_ingress, 'Response metrics (NGINX Ingress)' + it_behaves_like 'group_title', :ha_proxy, 'Response metrics (HA Proxy)' + it_behaves_like 'group_title', :aws_elb, 'Response metrics (AWS ELB)' + it_behaves_like 'group_title', :nginx, 'Response metrics (NGINX)' + it_behaves_like 'group_title', :kubernetes, 'System metrics (Kubernetes)' it_behaves_like 'group_title', :business, 'Business metrics (Custom)' it_behaves_like 'group_title', :response, 'Response metrics (Custom)' it_behaves_like 'group_title', :system, 'System metrics (Custom)' end + describe '#priority' do + using RSpec::Parameterized::TableSyntax + + where(:group, :priority) do + :nginx_ingress_vts | 10 + :nginx_ingress | 10 + :ha_proxy | 10 + :aws_elb | 10 + :nginx | 10 + :kubernetes | 5 + :business | 0 + :response | -5 + :system | -10 + end + + with_them do + before do + subject.group = group + end + + it { expect(subject.priority).to eq(priority) } + end + end + + describe '#required_metrics' do + using RSpec::Parameterized::TableSyntax + + where(:group, :required_metrics) do + :nginx_ingress_vts | %w(nginx_upstream_responses_total nginx_upstream_response_msecs_avg) + :nginx_ingress | %w(nginx_ingress_controller_requests nginx_ingress_controller_ingress_upstream_latency_seconds_sum) + :ha_proxy | %w(haproxy_frontend_http_requests_total haproxy_frontend_http_responses_total) + :aws_elb | %w(aws_elb_request_count_sum aws_elb_latency_average aws_elb_httpcode_backend_5_xx_sum) + :nginx | %w(nginx_server_requests nginx_server_requestMsec) + :kubernetes | %w(container_memory_usage_bytes container_cpu_usage_seconds_total) + :business | %w() + :response | %w() + :system | %w() + end + + with_them do + before do + subject.group = group + end + + it { expect(subject.required_metrics).to eq(required_metrics) } + end + end + describe '#to_query_metric' do it 'converts to queryable metric object' do expect(subject.to_query_metric).to be_instance_of(Gitlab::Prometheus::Metric) diff --git a/spec/models/release_spec.rb b/spec/models/release_spec.rb index 51725eeacac..92ba2d82f58 100644 --- a/spec/models/release_spec.rb +++ b/spec/models/release_spec.rb @@ -1,7 +1,9 @@ require 'rails_helper' RSpec.describe Release do - let(:release) { create(:release) } + let(:user) { create(:user) } + let(:project) { create(:project, :public, :repository) } + let(:release) { create(:release, project: project, author: user) } it { expect(release).to be_valid } diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb index baf21efa75c..be1804c5ce0 100644 --- a/spec/policies/group_policy_spec.rb +++ b/spec/policies/group_policy_spec.rb @@ -25,7 +25,8 @@ describe GroupPolicy do :read_cluster, :create_cluster, :update_cluster, - :admin_cluster + :admin_cluster, + :add_cluster ] end @@ -382,4 +383,14 @@ describe GroupPolicy do it { expect_disallowed(:change_share_with_group_lock) } end end + + it_behaves_like 'clusterable policies' do + let(:clusterable) { create(:group) } + let(:cluster) do + create(:cluster, + :provided_by_gcp, + :group, + groups: [clusterable]) + end + end end diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index 69468f9ad85..9cb20854f6e 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -15,7 +15,7 @@ describe ProjectPolicy do read_project_for_iids read_issue_iid read_merge_request_iid read_label read_milestone read_project_snippet read_project_member read_note create_project create_issue create_note upload_file create_merge_request_in - award_emoji + award_emoji read_release ] end @@ -38,7 +38,7 @@ describe ProjectPolicy do update_commit_status create_build update_build create_pipeline update_pipeline create_merge_request_from create_wiki push_code resolve_note create_container_image update_container_image - create_environment create_deployment + create_environment create_deployment create_release update_release ] end @@ -48,7 +48,7 @@ describe ProjectPolicy do update_deployment admin_project_snippet admin_project_member admin_note admin_wiki admin_project admin_commit_status admin_build admin_container_image - admin_pipeline admin_environment admin_deployment + admin_pipeline admin_environment admin_deployment destroy_release add_cluster ] end @@ -56,7 +56,7 @@ describe ProjectPolicy do %i[ download_code fork_project read_commit_status read_pipeline read_container_image build_download_code build_read_container_image - download_wiki_code + download_wiki_code read_release ] end @@ -183,7 +183,8 @@ describe ProjectPolicy do :create_pipeline_schedule, :read_pipeline_schedule, :update_pipeline_schedule, :admin_pipeline_schedule, :destroy_pipeline_schedule, :create_environment, :read_environment, :update_environment, :admin_environment, :destroy_environment, :create_cluster, :read_cluster, :update_cluster, :admin_cluster, - :create_deployment, :read_deployment, :update_deployment, :admin_deployment, :destroy_deployment + :create_deployment, :read_deployment, :update_deployment, :admin_deployment, :destroy_deployment, + :destroy_release ] expect_disallowed(*repository_permissions) @@ -465,4 +466,14 @@ describe ProjectPolicy do expect_disallowed(*maintainer_abilities) end end + + it_behaves_like 'clusterable policies' do + let(:clusterable) { create(:project, :repository) } + let(:cluster) do + create(:cluster, + :provided_by_gcp, + :project, + projects: [clusterable]) + end + end end diff --git a/spec/presenters/clusterable_presenter_spec.rb b/spec/presenters/clusterable_presenter_spec.rb index 4f4ae5e07c5..05afe5347d1 100644 --- a/spec/presenters/clusterable_presenter_spec.rb +++ b/spec/presenters/clusterable_presenter_spec.rb @@ -14,4 +14,68 @@ describe ClusterablePresenter do expect(subject).to be_kind_of(ProjectClusterablePresenter) end end + + shared_examples 'appropriate member permissions' do + context 'with a developer' do + before do + clusterable.add_developer(user) + end + + it { is_expected.to be_falsy } + end + + context 'with a maintainer' do + before do + clusterable.add_maintainer(user) + end + + it { is_expected.to be_truthy } + end + end + + describe '#can_create_cluster?' do + let(:user) { create(:user) } + + subject { described_class.new(clusterable).can_create_cluster? } + + before do + allow(clusterable).to receive(:current_user).and_return(user) + end + + context 'when clusterable is a group' do + let(:clusterable) { create(:group) } + + it_behaves_like 'appropriate member permissions' + end + + context 'when clusterable is a project' do + let(:clusterable) { create(:project, :repository) } + + it_behaves_like 'appropriate member permissions' + end + end + + describe '#can_add_cluster?' do + let(:user) { create(:user) } + + subject { described_class.new(clusterable).can_add_cluster? } + + before do + clusterable.add_maintainer(user) + + allow(clusterable).to receive(:current_user).and_return(user) + end + + context 'when clusterable is a group' do + let(:clusterable) { create(:group) } + + it_behaves_like 'appropriate member permissions' + end + + context 'when clusterable is a project' do + let(:clusterable) { create(:project, :repository) } + + it_behaves_like 'appropriate member permissions' + end + end end diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index 0ba1f2d7a2b..a0aee937185 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -190,7 +190,7 @@ describe API::Files do get api(url, current_user), params: params - expect(headers['Content-Disposition']).to match(/^attachment/) + expect(headers['Content-Disposition']).to eq('attachment; filename="popen.rb"') end context 'when mandatory params are not given' do diff --git a/spec/requests/api/releases_spec.rb b/spec/requests/api/releases_spec.rb new file mode 100644 index 00000000000..a44e37f9cd5 --- /dev/null +++ b/spec/requests/api/releases_spec.rb @@ -0,0 +1,532 @@ +require 'spec_helper' + +describe API::Releases do + let(:project) { create(:project, :repository, :private) } + let(:maintainer) { create(:user) } + let(:reporter) { create(:user) } + let(:non_project_member) { create(:user) } + let(:commit) { create(:commit, project: project) } + + before do + project.add_maintainer(maintainer) + project.add_reporter(reporter) + + project.repository.add_tag(maintainer, 'v0.1', commit.id) + project.repository.add_tag(maintainer, 'v0.2', commit.id) + end + + describe 'GET /projects/:id/releases' do + context 'when there are two releases' do + let!(:release_1) do + create(:release, + project: project, + tag: 'v0.1', + author: maintainer, + created_at: 2.days.ago) + end + + let!(:release_2) do + create(:release, + project: project, + tag: 'v0.2', + author: maintainer, + created_at: 1.day.ago) + end + + it 'returns 200 HTTP status' do + get api("/projects/#{project.id}/releases", maintainer) + + expect(response).to have_gitlab_http_status(:ok) + end + + it 'returns releases ordered by created_at' do + get api("/projects/#{project.id}/releases", maintainer) + + expect(json_response.count).to eq(2) + expect(json_response.first['tag_name']).to eq(release_2.tag) + expect(json_response.second['tag_name']).to eq(release_1.tag) + end + + it 'matches response schema' do + get api("/projects/#{project.id}/releases", maintainer) + + expect(response).to match_response_schema('releases') + end + end + + context 'when tag does not exist in git repository' do + let!(:release) { create(:release, project: project, tag: 'v1.1.5') } + + it 'returns the tag' do + get api("/projects/#{project.id}/releases", maintainer) + + expect(json_response.count).to eq(1) + expect(json_response.first['tag_name']).to eq('v1.1.5') + expect(release).to be_tag_missing + end + end + + context 'when user is not a project member' do + it 'cannot find the project' do + get api("/projects/#{project.id}/releases", non_project_member) + + expect(response).to have_gitlab_http_status(:not_found) + end + + context 'when project is public' do + let(:project) { create(:project, :repository, :public) } + + it 'allows the request' do + get api("/projects/#{project.id}/releases", non_project_member) + + expect(response).to have_gitlab_http_status(:ok) + end + end + end + + context 'when feature flag is disabled' do + before do + stub_feature_flags(releases_page: false) + end + + it 'cannot find the API' do + get api("/projects/#{project.id}/releases", maintainer) + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + describe 'GET /projects/:id/releases/:tag_name' do + context 'when there is a release' do + let!(:release) do + create(:release, + project: project, + tag: 'v0.1', + sha: commit.id, + author: maintainer, + description: 'This is v0.1') + end + + it 'returns 200 HTTP status' do + get api("/projects/#{project.id}/releases/v0.1", maintainer) + + expect(response).to have_gitlab_http_status(:ok) + end + + it 'returns a release entry' do + get api("/projects/#{project.id}/releases/v0.1", maintainer) + + expect(json_response['tag_name']).to eq(release.tag) + expect(json_response['description']).to eq('This is v0.1') + expect(json_response['author']['name']).to eq(maintainer.name) + expect(json_response['commit']['id']).to eq(commit.id) + end + + it 'matches response schema' do + get api("/projects/#{project.id}/releases/v0.1", maintainer) + + expect(response).to match_response_schema('release') + end + end + + context 'when specified tag is not found in the project' do + it 'cannot find the release entry' do + get api("/projects/#{project.id}/releases/non_exist_tag", maintainer) + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + context 'when user is not a project member' do + let!(:release) { create(:release, tag: 'v0.1', project: project) } + + it 'cannot find the project' do + get api("/projects/#{project.id}/releases/v0.1", non_project_member) + + expect(response).to have_gitlab_http_status(:not_found) + end + + context 'when project is public' do + let(:project) { create(:project, :repository, :public) } + + it 'allows the request' do + get api("/projects/#{project.id}/releases/v0.1", non_project_member) + + expect(response).to have_gitlab_http_status(:ok) + end + end + end + + context 'when feature flag is disabled' do + before do + stub_feature_flags(releases_page: false) + end + + it 'cannot find the API' do + get api("/projects/#{project.id}/releases/v0.1", maintainer) + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + describe 'POST /projects/:id/releases' do + let(:params) do + { + name: 'New release', + tag_name: 'v0.1', + description: 'Super nice release' + } + end + + it 'accepts the request' do + post api("/projects/#{project.id}/releases", maintainer), params: params + + expect(response).to have_gitlab_http_status(:created) + end + + it 'creates a new release' do + expect do + post api("/projects/#{project.id}/releases", maintainer), params: params + end.to change { Release.count }.by(1) + + expect(project.releases.last.name).to eq('New release') + expect(project.releases.last.tag).to eq('v0.1') + expect(project.releases.last.description).to eq('Super nice release') + end + + context 'when description is empty' do + let(:params) do + { + name: 'New release', + tag_name: 'v0.1', + description: '' + } + end + + it 'returns an error as validation failure' do + expect do + post api("/projects/#{project.id}/releases", maintainer), params: params + end.not_to change { Release.count } + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['message']) + .to eq("Validation failed: Description can't be blank") + end + end + + it 'matches response schema' do + post api("/projects/#{project.id}/releases", maintainer), params: params + + expect(response).to match_response_schema('release') + end + + it 'does not create a new tag' do + expect do + post api("/projects/#{project.id}/releases", maintainer), params: params + end.not_to change { Project.find_by_id(project.id).repository.tag_count } + end + + context 'when user is a reporter' do + it 'forbids the request' do + post api("/projects/#{project.id}/releases", reporter), params: params + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + context 'when user is not a project member' do + it 'forbids the request' do + post api("/projects/#{project.id}/releases", non_project_member), + params: params + + expect(response).to have_gitlab_http_status(:not_found) + end + + context 'when project is public' do + let(:project) { create(:project, :repository, :public) } + + it 'forbids the request' do + post api("/projects/#{project.id}/releases", non_project_member), + params: params + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + end + + context 'when tag does not exist in git repository' do + let(:params) do + { + name: 'Android ~ Ice Cream Sandwich ~', + tag_name: tag_name, + description: 'Android 4.0–4.0.4 "Ice Cream Sandwich" is the ninth' \ + 'version of the Android mobile operating system developed' \ + 'by Google.', + ref: 'master' + } + end + + let(:tag_name) { 'v4.0' } + + it 'creates a new tag' do + expect do + post api("/projects/#{project.id}/releases", maintainer), params: params + end.to change { Project.find_by_id(project.id).repository.tag_count }.by(1) + + expect(project.repository.find_tag('v4.0').dereferenced_target.id) + .to eq(project.repository.commit('master').id) + end + + it 'creates a new release' do + expect do + post api("/projects/#{project.id}/releases", maintainer), params: params + end.to change { Release.count }.by(1) + + expect(project.releases.last.name).to eq('Android ~ Ice Cream Sandwich ~') + expect(project.releases.last.tag).to eq('v4.0') + expect(project.releases.last.description).to eq( + 'Android 4.0–4.0.4 "Ice Cream Sandwich" is the ninth' \ + 'version of the Android mobile operating system developed' \ + 'by Google.') + end + + context 'when tag name is HEAD' do + let(:tag_name) { 'HEAD' } + + it 'returns an error as failure on tag creation' do + post api("/projects/#{project.id}/releases", maintainer), params: params + + expect(response).to have_gitlab_http_status(:internal_server_error) + expect(json_response['message']).to eq('Tag name invalid') + end + end + + context 'when tag name is empty' do + let(:tag_name) { '' } + + it 'returns an error as failure on tag creation' do + post api("/projects/#{project.id}/releases", maintainer), params: params + + expect(response).to have_gitlab_http_status(:internal_server_error) + expect(json_response['message']).to eq('Tag name invalid') + end + end + end + + context 'when release already exists' do + before do + create(:release, project: project, tag: 'v0.1', name: 'New release') + end + + it 'returns an error as conflicted request' do + post api("/projects/#{project.id}/releases", maintainer), params: params + + expect(response).to have_gitlab_http_status(:conflict) + end + end + + context 'when feature flag is disabled' do + before do + stub_feature_flags(releases_page: false) + end + + it 'cannot find the API' do + post api("/projects/#{project.id}/releases", maintainer), params: params + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + describe 'PUT /projects/:id/releases/:tag_name' do + let(:params) { { description: 'Best release ever!' } } + + let!(:release) do + create(:release, + project: project, + tag: 'v0.1', + name: 'New release', + description: 'Super nice release') + end + + it 'accepts the request' do + put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params + + expect(response).to have_gitlab_http_status(:ok) + end + + it 'updates the description' do + put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params + + expect(project.releases.last.description).to eq('Best release ever!') + end + + it 'does not change other attributes' do + put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params + + expect(project.releases.last.tag).to eq('v0.1') + expect(project.releases.last.name).to eq('New release') + end + + it 'matches response schema' do + put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params + + expect(response).to match_response_schema('release') + end + + context 'when user tries to update sha' do + let(:params) { { sha: 'xxx' } } + + it 'does not allow the request' do + put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params + + expect(response).to have_gitlab_http_status(:bad_request) + end + end + + context 'when params is empty' do + let(:params) { {} } + + it 'does not allow the request' do + put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params + + expect(response).to have_gitlab_http_status(:bad_request) + end + end + + context 'when there are no corresponding releases' do + let!(:release) { } + + it 'forbids the request' do + put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + context 'when user is a reporter' do + it 'forbids the request' do + put api("/projects/#{project.id}/releases/v0.1", reporter), params: params + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + context 'when user is not a project member' do + it 'forbids the request' do + put api("/projects/#{project.id}/releases/v0.1", non_project_member), + params: params + + expect(response).to have_gitlab_http_status(:not_found) + end + + context 'when project is public' do + let(:project) { create(:project, :repository, :public) } + + it 'forbids the request' do + put api("/projects/#{project.id}/releases/v0.1", non_project_member), + params: params + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + end + + context 'when feature flag is disabled' do + before do + stub_feature_flags(releases_page: false) + end + + it 'cannot find the API' do + put api("/projects/#{project.id}/releases/v0.1", non_project_member), + params: params + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + describe 'DELETE /projects/:id/releases/:tag_name' do + let!(:release) do + create(:release, + project: project, + tag: 'v0.1', + name: 'New release', + description: 'Super nice release') + end + + it 'accepts the request' do + delete api("/projects/#{project.id}/releases/v0.1", maintainer) + + expect(response).to have_gitlab_http_status(:ok) + end + + it 'destroys the release' do + expect do + delete api("/projects/#{project.id}/releases/v0.1", maintainer) + end.to change { Release.count }.by(-1) + end + + it 'does not remove a tag in repository' do + expect do + delete api("/projects/#{project.id}/releases/v0.1", maintainer) + end.not_to change { Project.find_by_id(project.id).repository.tag_count } + end + + it 'matches response schema' do + delete api("/projects/#{project.id}/releases/v0.1", maintainer) + + expect(response).to match_response_schema('release') + end + + context 'when there are no corresponding releases' do + let!(:release) { } + + it 'forbids the request' do + delete api("/projects/#{project.id}/releases/v0.1", maintainer) + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + context 'when user is a reporter' do + it 'forbids the request' do + delete api("/projects/#{project.id}/releases/v0.1", reporter) + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + context 'when user is not a project member' do + it 'forbids the request' do + delete api("/projects/#{project.id}/releases/v0.1", non_project_member) + + expect(response).to have_gitlab_http_status(:not_found) + end + + context 'when project is public' do + let(:project) { create(:project, :repository, :public) } + + it 'forbids the request' do + delete api("/projects/#{project.id}/releases/v0.1", non_project_member) + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + end + + context 'when feature flag is disabled' do + before do + stub_feature_flags(releases_page: false) + end + + it 'cannot find the API' do + delete api("/projects/#{project.id}/releases/v0.1", non_project_member) + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end +end diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index 181fe6246ae..b6b57803a6a 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -171,7 +171,7 @@ describe API::Repositories do it 'forces attachment content disposition' do get api(route, current_user) - expect(headers['Content-Disposition']).to match(/^attachment/) + expect(headers['Content-Disposition']).to eq 'attachment' end context 'when sha does not exist' do diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb index 12cfac96d31..d09b6fe72b1 100644 --- a/spec/requests/api/tags_spec.rb +++ b/spec/requests/api/tags_spec.rb @@ -107,9 +107,12 @@ describe API::Tags do context 'with releases' do let(:description) { 'Awesome release!' } - before do - release = project.releases.find_or_initialize_by(tag: tag_name) - release.update(description: description) + let!(:release) do + create(:release, + :legacy, + project: project, + tag: tag_name, + description: description) end it 'returns an array of project tags with release info' do @@ -373,7 +376,7 @@ describe API::Tags do it_behaves_like '404 response' do let(:request) { post api(route, current_user), params: { description: description } } - let(:message) { 'Tag does not exist' } + let(:message) { '404 Tag Not Found' } end end @@ -398,10 +401,7 @@ describe API::Tags do end context 'on tag with existing release' do - before do - release = project.releases.find_or_initialize_by(tag: tag_name) - release.update(description: description) - end + let!(:release) { create(:release, :legacy, project: project, tag: tag_name, description: description) } it 'returns 409 if there is already a release' do post api(route, user), params: { description: description } @@ -420,9 +420,12 @@ describe API::Tags do shared_examples_for 'repository update release' do context 'on tag with existing release' do - before do - release = project.releases.find_or_initialize_by(tag: tag_name) - release.update(description: description) + let!(:release) do + create(:release, + :legacy, + project: project, + tag: tag_name, + description: description) end it 'updates the release description' do @@ -437,9 +440,9 @@ describe API::Tags do context 'when tag does not exist' do let(:tag_name) { 'unknown' } - it_behaves_like '404 response' do + it_behaves_like '403 response' do let(:request) { put api(route, current_user), params: { description: new_description } } - let(:message) { 'Tag does not exist' } + let(:message) { '403 Forbidden' } end end @@ -464,9 +467,9 @@ describe API::Tags do end context 'when release does not exist' do - it_behaves_like '404 response' do + it_behaves_like '403 response' do let(:request) { put api(route, current_user), params: { description: new_description } } - let(:message) { 'Release does not exist' } + let(:message) { '403 Forbidden' } end end end diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb index f2e9799452a..8021bd338e0 100644 --- a/spec/services/auth/container_registry_authentication_service_spec.rb +++ b/spec/services/auth/container_registry_authentication_service_spec.rb @@ -5,7 +5,7 @@ describe Auth::ContainerRegistryAuthenticationService do let(:current_user) { nil } let(:current_params) { {} } let(:rsa_key) { OpenSSL::PKey::RSA.generate(512) } - let(:payload) { JWT.decode(subject[:token], rsa_key).first } + let(:payload) { JWT.decode(subject[:token], rsa_key, true, { algorithm: 'RS256' }).first } let(:authentication_abilities) do [:read_container_image, :create_container_image, :admin_container_image] diff --git a/spec/services/create_release_service_spec.rb b/spec/services/create_release_service_spec.rb deleted file mode 100644 index 1a2dd0b39ee..00000000000 --- a/spec/services/create_release_service_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -require 'spec_helper' - -describe CreateReleaseService do - let(:project) { create(:project, :repository) } - let(:user) { create(:user) } - let(:tag_name) { project.repository.tag_names.first } - let(:description) { 'Awesome release!' } - let(:service) { described_class.new(project, user) } - let(:tag) { project.repository.find_tag(tag_name) } - let(:sha) { tag.dereferenced_target.sha } - - it 'creates a new release' do - result = service.execute(tag_name, description) - expect(result[:status]).to eq(:success) - release = project.releases.find_by(tag: tag_name) - expect(release).not_to be_nil - expect(release.description).to eq(description) - expect(release.name).to eq(tag_name) - expect(release.sha).to eq(sha) - expect(release.author).to eq(user) - end - - it 'raises an error if the tag does not exist' do - result = service.execute("foobar", description) - expect(result[:status]).to eq(:error) - end - - context 'there already exists a release on a tag' do - before do - service.execute(tag_name, description) - end - - it 'raises an error and does not update the release' do - result = service.execute(tag_name, 'The best release!') - expect(result[:status]).to eq(:error) - expect(project.releases.find_by(tag: tag_name).description).to eq(description) - end - end -end diff --git a/spec/services/releases/create_service_spec.rb b/spec/services/releases/create_service_spec.rb new file mode 100644 index 00000000000..612e9f152e7 --- /dev/null +++ b/spec/services/releases/create_service_spec.rb @@ -0,0 +1,72 @@ +require 'spec_helper' + +describe Releases::CreateService do + let(:project) { create(:project, :repository) } + let(:user) { create(:user) } + let(:tag_name) { project.repository.tag_names.first } + let(:tag_sha) { project.repository.find_tag(tag_name).dereferenced_target.sha } + let(:name) { 'Bionic Beaver' } + let(:description) { 'Awesome release!' } + let(:params) { { tag: tag_name, name: name, description: description, ref: ref } } + let(:ref) { nil } + let(:service) { described_class.new(project, user, params) } + + before do + project.add_maintainer(user) + end + + describe '#execute' do + shared_examples 'a successful release creation' do + it 'creates a new release' do + result = service.execute + expect(result[:status]).to eq(:success) + expect(result[:tag]).not_to be_nil + expect(result[:release]).not_to be_nil + expect(result[:release].description).to eq(description) + expect(result[:release].name).to eq(name) + expect(result[:release].author).to eq(user) + expect(result[:release].sha).to eq(tag_sha) + end + end + + it_behaves_like 'a successful release creation' + + context 'when the tag does not exist' do + let(:tag_name) { 'non-exist-tag' } + + it 'raises an error' do + result = service.execute + + expect(result[:status]).to eq(:error) + end + end + + context 'when ref is provided' do + let(:ref) { 'master' } + let(:tag_name) { 'foobar' } + + it_behaves_like 'a successful release creation' + + it 'creates a tag if the tag does not exist' do + expect(project.repository.ref_exists?("refs/tags/#{tag_name}")).to be_falsey + + result = service.execute + expect(result[:status]).to eq(:success) + expect(result[:tag]).not_to be_nil + expect(result[:release]).not_to be_nil + end + end + + context 'there already exists a release on a tag' do + let!(:release) do + create(:release, project: project, tag: tag_name, description: description) + end + + it 'raises an error and does not update the release' do + result = service.execute + expect(result[:status]).to eq(:error) + expect(project.releases.find_by(tag: tag_name).description).to eq(description) + end + end + end +end diff --git a/spec/services/releases/destroy_service_spec.rb b/spec/services/releases/destroy_service_spec.rb new file mode 100644 index 00000000000..dd5b8708f36 --- /dev/null +++ b/spec/services/releases/destroy_service_spec.rb @@ -0,0 +1,61 @@ +require 'spec_helper' + +describe Releases::DestroyService do + let(:project) { create(:project, :repository) } + let(:mainatiner) { create(:user) } + let(:repoter) { create(:user) } + let(:tag) { 'v1.1.0' } + let!(:release) { create(:release, project: project, tag: tag) } + let(:service) { described_class.new(project, user, params) } + let(:params) { { tag: tag } } + let(:user) { mainatiner } + + before do + project.add_maintainer(mainatiner) + project.add_reporter(repoter) + end + + describe '#execute' do + subject { service.execute } + + context 'when there is a release' do + it 'removes the release' do + expect { subject }.to change { project.releases.count }.by(-1) + end + + it 'returns the destroyed object' do + is_expected.to include(status: :success, release: release) + end + end + + context 'when tag is not found' do + let(:tag) { 'v1.1.1' } + + it 'returns an error' do + is_expected.to include(status: :error, + message: 'Tag does not exist', + http_status: 404) + end + end + + context 'when release is not found' do + let!(:release) { } + + it 'returns an error' do + is_expected.to include(status: :error, + message: 'Release does not exist', + http_status: 404) + end + end + + context 'when user does not have permission' do + let(:user) { repoter } + + it 'returns an error' do + is_expected.to include(status: :error, + message: 'Access Denied', + http_status: 403) + end + end + end +end diff --git a/spec/services/releases/update_service_spec.rb b/spec/services/releases/update_service_spec.rb new file mode 100644 index 00000000000..6c68f364739 --- /dev/null +++ b/spec/services/releases/update_service_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +describe Releases::UpdateService do + let(:project) { create(:project, :repository) } + let(:user) { create(:user) } + let(:new_name) { 'A new name' } + let(:new_description) { 'The best release!' } + let(:params) { { name: new_name, description: new_description, tag: tag_name } } + let(:service) { described_class.new(project, user, params) } + let!(:release) { create(:release, project: project, author: user, tag: tag_name) } + let(:tag_name) { 'v1.1.0' } + + before do + project.add_developer(user) + end + + describe '#execute' do + shared_examples 'a failed update' do + it 'raises an error' do + result = service.execute + expect(result[:status]).to eq(:error) + end + end + + it 'successfully updates an existing release' do + result = service.execute + expect(result[:status]).to eq(:success) + expect(result[:release].name).to eq(new_name) + expect(result[:release].description).to eq(new_description) + end + + context 'when the tag does not exists' do + let(:tag_name) { 'foobar' } + + it_behaves_like 'a failed update' + end + + context 'when the release does not exist' do + let!(:release) { } + + it_behaves_like 'a failed update' + end + + context 'with an invalid update' do + let(:new_description) { '' } + + it_behaves_like 'a failed update' + end + end +end diff --git a/spec/services/update_release_service_spec.rb b/spec/services/update_release_service_spec.rb deleted file mode 100644 index dc2d0e2d47a..00000000000 --- a/spec/services/update_release_service_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -require 'spec_helper' - -describe UpdateReleaseService do - let(:project) { create(:project, :repository) } - let(:user) { create(:user) } - let(:tag_name) { project.repository.tag_names.first } - let(:description) { 'Awesome release!' } - let(:new_description) { 'The best release!' } - let(:service) { described_class.new(project, user) } - - context 'with an existing release' do - let(:create_service) { CreateReleaseService.new(project, user) } - - before do - create_service.execute(tag_name, description) - end - - it 'successfully updates an existing release' do - result = service.execute(tag_name, new_description) - expect(result[:status]).to eq(:success) - expect(project.releases.find_by(tag: tag_name).description).to eq(new_description) - end - end - - it 'raises an error if the tag does not exist' do - result = service.execute("foobar", description) - expect(result[:status]).to eq(:error) - end - - it 'raises an error if the release does not exist' do - result = service.execute(tag_name, description) - expect(result[:status]).to eq(:error) - end -end diff --git a/spec/support/helpers/fake_blob_helpers.rb b/spec/support/helpers/fake_blob_helpers.rb index bc9686ed9cf..801ca8b7412 100644 --- a/spec/support/helpers/fake_blob_helpers.rb +++ b/spec/support/helpers/fake_blob_helpers.rb @@ -23,7 +23,7 @@ module FakeBlobHelpers 0 end - def binary? + def binary_in_repo? @binary end diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb index d52c40ff4f1..d352a7cdf1a 100644 --- a/spec/support/helpers/test_env.rb +++ b/spec/support/helpers/test_env.rb @@ -62,7 +62,8 @@ module TestEnv 'between-create-delete-modify-move' => '3f5f443', 'after-create-delete-modify-move' => 'ba3faa7', 'with-codeowners' => '219560e', - 'submodule_inside_folder' => 'b491b92' + 'submodule_inside_folder' => 'b491b92', + 'png-lfs' => 'fe42f41' }.freeze # gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily diff --git a/spec/support/shared_examples/policies/clusterable_shared_examples.rb b/spec/support/shared_examples/policies/clusterable_shared_examples.rb new file mode 100644 index 00000000000..d99f94c76c3 --- /dev/null +++ b/spec/support/shared_examples/policies/clusterable_shared_examples.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +shared_examples 'clusterable policies' do + describe '#add_cluster?' do + let(:current_user) { create(:user) } + + subject { described_class.new(current_user, clusterable) } + + context 'with a developer' do + before do + clusterable.add_developer(current_user) + end + + it { expect_disallowed(:add_cluster) } + end + + context 'with a maintainer' do + before do + clusterable.add_maintainer(current_user) + end + + context 'with no clusters' do + it { expect_allowed(:add_cluster) } + end + + context 'with an existing cluster' do + before do + cluster + end + + it { expect_disallowed(:add_cluster) } + end + end + end +end |