diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-18 11:17:02 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-18 11:17:02 +0300 |
commit | b39512ed755239198a9c294b6a45e65c05900235 (patch) | |
tree | d234a3efade1de67c46b9e5a38ce813627726aa7 /spec/requests/projects | |
parent | d31474cf3b17ece37939d20082b07f6657cc79a9 (diff) |
Add latest changes from gitlab-org/gitlab@15-3-stable-eev15.3.0-rc42
Diffstat (limited to 'spec/requests/projects')
4 files changed, 375 insertions, 165 deletions
diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb index 89d46b64311..65540f86d34 100644 --- a/spec/requests/projects/cycle_analytics_events_spec.rb +++ b/spec/requests/projects/cycle_analytics_events_spec.rb @@ -3,13 +3,15 @@ require 'spec_helper' RSpec.describe 'value stream analytics events' do + include CycleAnalyticsHelpers + let(:user) { create(:user) } let(:project) { create(:project, :repository, public_builds: false) } let(:issue) { create(:issue, project: project, created_at: 2.days.ago) } describe 'GET /:namespace/:project/value_stream_analytics/events/issues' do - let(:first_issue_iid) { project.issues.sort_by_attribute(:created_desc).pluck(:iid).first.to_s } - let(:first_mr_iid) { project.merge_requests.sort_by_attribute(:created_desc).pluck(:iid).first.to_s } + let(:first_issue_iid) { project.issues.sort_by_attribute(:created_desc).pick(:iid).to_s } + let(:first_mr_iid) { project.merge_requests.sort_by_attribute(:created_desc).pick(:iid).to_s } before do project.add_developer(user) diff --git a/spec/requests/projects/merge_requests/diffs_spec.rb b/spec/requests/projects/merge_requests/diffs_spec.rb index e17be1ff984..937b0f1d713 100644 --- a/spec/requests/projects/merge_requests/diffs_spec.rb +++ b/spec/requests/projects/merge_requests/diffs_spec.rb @@ -13,8 +13,6 @@ RSpec.describe 'Merge Requests Diffs' do end describe 'GET diffs_batch' do - let(:headers) { {} } - shared_examples_for 'serializes diffs with expected arguments' do it 'serializes paginated merge request diff collection' do expect_next_instance_of(PaginatedDiffSerializer) do |instance| @@ -24,6 +22,8 @@ RSpec.describe 'Merge Requests Diffs' do end subject + + expect(response).to have_gitlab_http_status(:success) end end @@ -40,7 +40,7 @@ RSpec.describe 'Merge Requests Diffs' do } end - def go(extra_params = {}) + def go(headers: {}, **extra_params) params = { namespace_id: project.namespace.to_param, project_id: project, @@ -54,13 +54,15 @@ RSpec.describe 'Merge Requests Diffs' do end context 'with caching', :use_clean_rails_memory_store_caching do - subject { go(page: 0, per_page: 5) } + subject { go(headers: headers, page: 0, per_page: 5) } + + let(:headers) { {} } context 'when the request has not been cached' do - it_behaves_like 'serializes diffs with expected arguments' do - let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } - let(:expected_options) { collection_arguments(total_pages: 20) } - end + let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } + let(:expected_options) { collection_arguments(total_pages: 20) } + + it_behaves_like 'serializes diffs with expected arguments' end context 'when the request has already been cached' do @@ -76,21 +78,61 @@ RSpec.describe 'Merge Requests Diffs' do subject end + context 'when using ETags' do + context 'when etag_merge_request_diff_batches is true' do + let(:headers) { { 'If-None-Match' => response.etag } } + + it 'does not serialize diffs' do + expect(PaginatedDiffSerializer).not_to receive(:new) + + go(headers: headers, page: 0, per_page: 5) + + expect(response).to have_gitlab_http_status(:not_modified) + end + end + + context 'when etag_merge_request_diff_batches is false' do + let(:headers) { { 'If-None-Match' => response.etag } } + + before do + stub_feature_flags(etag_merge_request_diff_batches: false) + end + + it 'does not serialize diffs' do + expect_next_instance_of(PaginatedDiffSerializer) do |instance| + expect(instance).not_to receive(:represent) + end + + subject + + expect(response).to have_gitlab_http_status(:success) + end + end + end + context 'with the different user' do let(:another_user) { create(:user) } + let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } + let(:expected_options) { collection_arguments(total_pages: 20) } before do project.add_maintainer(another_user) sign_in(another_user) end - it_behaves_like 'serializes diffs with expected arguments' do - let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } - let(:expected_options) { collection_arguments(total_pages: 20) } + it_behaves_like 'serializes diffs with expected arguments' + + context 'when using ETag caching' do + it_behaves_like 'serializes diffs with expected arguments' do + let(:headers) { { 'If-None-Match' => response.etag } } + end end end context 'with a new unfoldable diff position' do + let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } + let(:expected_options) { collection_arguments(total_pages: 20) } + let(:unfoldable_position) do create(:diff_position) end @@ -103,80 +145,155 @@ RSpec.describe 'Merge Requests Diffs' do end end - it_behaves_like 'serializes diffs with expected arguments' do - let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } - let(:expected_options) { collection_arguments(total_pages: 20) } + it_behaves_like 'serializes diffs with expected arguments' + + context 'when using ETag caching' do + it_behaves_like 'serializes diffs with expected arguments' do + let(:headers) { { 'If-None-Match' => response.etag } } + end end end context 'with disabled display_merge_conflicts_in_diff feature' do + let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } + let(:expected_options) { collection_arguments(total_pages: 20).merge(allow_tree_conflicts: false) } + before do stub_feature_flags(display_merge_conflicts_in_diff: false) end - it_behaves_like 'serializes diffs with expected arguments' do - let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } - let(:expected_options) { collection_arguments(total_pages: 20).merge(allow_tree_conflicts: false) } + it_behaves_like 'serializes diffs with expected arguments' + + context 'when using ETag caching' do + it_behaves_like 'serializes diffs with expected arguments' do + let(:headers) { { 'If-None-Match' => response.etag } } + end end end context 'with diff_head option' do subject { go(page: 0, per_page: 5, diff_head: true) } + let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } + let(:expected_options) { collection_arguments(total_pages: 20).merge(merge_ref_head_diff: true) } + before do merge_request.create_merge_head_diff! end - it_behaves_like 'serializes diffs with expected arguments' do - let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } - let(:expected_options) { collection_arguments(total_pages: 20).merge(merge_ref_head_diff: true) } + it_behaves_like 'serializes diffs with expected arguments' + + context 'when using ETag caching' do + it_behaves_like 'serializes diffs with expected arguments' do + let(:headers) { { 'If-None-Match' => response.etag } } + end end end context 'with the different pagination option' do subject { go(page: 5, per_page: 5) } - it_behaves_like 'serializes diffs with expected arguments' do - let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } - let(:expected_options) { collection_arguments(total_pages: 20) } + let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } + let(:expected_options) { collection_arguments(total_pages: 20) } + + it_behaves_like 'serializes diffs with expected arguments' + + context 'when using ETag caching' do + it_behaves_like 'serializes diffs with expected arguments' do + let(:headers) { { 'If-None-Match' => response.etag } } + end end end context 'with the different diff_view' do subject { go(page: 0, per_page: 5, view: :parallel) } - it_behaves_like 'serializes diffs with expected arguments' do - let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } - let(:expected_options) { collection_arguments(total_pages: 20).merge(diff_view: :parallel) } + let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } + let(:expected_options) { collection_arguments(total_pages: 20).merge(diff_view: :parallel) } + + it_behaves_like 'serializes diffs with expected arguments' + + context 'when using ETag caching' do + it_behaves_like 'serializes diffs with expected arguments' do + let(:headers) { { 'If-None-Match' => response.etag } } + end end end context 'with the different expanded option' do subject { go(page: 0, per_page: 5, expanded: true ) } - it_behaves_like 'serializes diffs with expected arguments' do - let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } - let(:expected_options) { collection_arguments(total_pages: 20) } + let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } + let(:expected_options) { collection_arguments(total_pages: 20) } + + it_behaves_like 'serializes diffs with expected arguments' + + context 'when using ETag caching' do + it_behaves_like 'serializes diffs with expected arguments' do + let(:headers) { { 'If-None-Match' => response.etag } } + end end end context 'with the different ignore_whitespace_change option' do subject { go(page: 0, per_page: 5, w: 1) } - it_behaves_like 'serializes diffs with expected arguments' do - let(:collection) { Gitlab::Diff::FileCollection::Compare } - let(:expected_options) { collection_arguments(total_pages: 20) } + let(:collection) { Gitlab::Diff::FileCollection::Compare } + let(:expected_options) { collection_arguments(total_pages: 20) } + + it_behaves_like 'serializes diffs with expected arguments' + + context 'when using ETag caching' do + it_behaves_like 'serializes diffs with expected arguments' do + let(:headers) { { 'If-None-Match' => response.etag } } + end end end end context 'when the paths is given' do - subject { go(page: 0, per_page: 5, paths: %w[README CHANGELOG]) } + subject { go(headers: headers, page: 0, per_page: 5, paths: %w[README CHANGELOG]) } + + before do + go(page: 0, per_page: 5, paths: %w[README CHANGELOG]) + end - it 'does not use cache' do - expect(Rails.cache).not_to receive(:fetch).with(/cache:gitlab:PaginatedDiffSerializer/).and_call_original + context 'when using ETag caching' do + let(:headers) { { 'If-None-Match' => response.etag } } - subject + context 'when etag_merge_request_diff_batches is true' do + it 'does not serialize diffs' do + expect(PaginatedDiffSerializer).not_to receive(:new) + + subject + + expect(response).to have_gitlab_http_status(:not_modified) + end + end + + context 'when etag_merge_request_diff_batches is false' do + before do + stub_feature_flags(etag_merge_request_diff_batches: false) + end + + it 'does not use cache' do + expect(Rails.cache).not_to receive(:fetch).with(/cache:gitlab:PaginatedDiffSerializer/).and_call_original + + subject + + expect(response).to have_gitlab_http_status(:success) + end + end + end + + context 'when not using ETag caching' do + it 'does not use cache' do + expect(Rails.cache).not_to receive(:fetch).with(/cache:gitlab:PaginatedDiffSerializer/).and_call_original + + subject + + expect(response).to have_gitlab_http_status(:success) + end end end end diff --git a/spec/requests/projects/merge_requests_discussions_spec.rb b/spec/requests/projects/merge_requests_discussions_spec.rb index c761af86c16..9503dafcf2a 100644 --- a/spec/requests/projects/merge_requests_discussions_spec.rb +++ b/spec/requests/projects/merge_requests_discussions_spec.rb @@ -16,9 +16,16 @@ RSpec.describe 'merge requests discussions' do login_as(user) end + # rubocop:disable RSpec/InstanceVariable def send_request - get discussions_namespace_project_merge_request_path(namespace_id: project.namespace, project_id: project, id: merge_request.iid) + get( + discussions_namespace_project_merge_request_path(namespace_id: project.namespace, project_id: project, id: merge_request.iid), + headers: { 'If-None-Match' => @etag } + ) + + @etag = response.etag end + # rubocop:enable RSpec/InstanceVariable it 'returns 200' do send_request @@ -63,11 +70,6 @@ RSpec.describe 'merge requests discussions' do let!(:award_emoji) { create(:award_emoji, awardable: first_note) } let!(:author_membership) { project.add_maintainer(author) } - before do - # Make a request to cache the discussions - send_request - end - shared_examples 'cache miss' do it 'does not hit a warm cache' do expect_next_instance_of(DiscussionSerializer) do |serializer| @@ -80,176 +82,195 @@ RSpec.describe 'merge requests discussions' do end end - it 'gets cached on subsequent requests' do - expect_next_instance_of(DiscussionSerializer) do |serializer| - expect(serializer).not_to receive(:represent) - end + shared_examples 'cache hit' do + it 'gets cached on subsequent requests' do + expect_next_instance_of(DiscussionSerializer) do |serializer| + expect(serializer).not_to receive(:represent) + end - send_request + send_request + end end - context 'when a note in a discussion got updated' do + context 'when mr_discussions_http_cache and disabled_mr_discussions_redis_cache are enabled' do before do - first_note.update!(updated_at: 1.minute.from_now) + send_request end - it_behaves_like 'cache miss' do - let(:changed_notes) { [first_note, second_note] } - end - end + it_behaves_like 'cache hit' - context 'when a note in a discussion got its reference state updated' do - before do - reference.close! - end + context 'when a note in a discussion got updated' do + before do + first_note.update!(updated_at: 1.minute.from_now) + end - it_behaves_like 'cache miss' do - let(:changed_notes) { [first_note, second_note] } + it_behaves_like 'cache miss' do + let(:changed_notes) { [first_note, second_note] } + end end - end - context 'when a note in a discussion got resolved' do - before do - travel_to(1.minute.from_now) do - first_note.resolve!(user) + context 'when a note in a discussion got its reference state updated' do + before do + reference.close! end - end - it_behaves_like 'cache miss' do - let(:changed_notes) { [first_note, second_note] } + it_behaves_like 'cache miss' do + let(:changed_notes) { [first_note, second_note] } + end end - end - context 'when a note is added to a discussion' do - let!(:third_note) { create(:diff_note_on_merge_request, in_reply_to: first_note, noteable: merge_request, project: project) } + context 'when a note in a discussion got resolved' do + before do + travel_to(1.minute.from_now) do + first_note.resolve!(user) + end + end - it_behaves_like 'cache miss' do - let(:changed_notes) { [first_note, second_note, third_note] } + it_behaves_like 'cache miss' do + let(:changed_notes) { [first_note, second_note] } + end end - end - context 'when a note is removed from a discussion' do - before do - second_note.destroy! - end + context 'when a note is added to a discussion' do + let!(:third_note) { create(:diff_note_on_merge_request, in_reply_to: first_note, noteable: merge_request, project: project) } - it_behaves_like 'cache miss' do - let(:changed_notes) { [first_note] } + it_behaves_like 'cache miss' do + let(:changed_notes) { [first_note, second_note, third_note] } + end end - end - context 'when an emoji is awarded to a note in discussion' do - before do - travel_to(1.minute.from_now) do - create(:award_emoji, awardable: first_note) + context 'when a note is removed from a discussion' do + before do + second_note.destroy! end - end - it_behaves_like 'cache miss' do - let(:changed_notes) { [first_note, second_note] } + it_behaves_like 'cache miss' do + let(:changed_notes) { [first_note] } + end end - end - context 'when an award emoji is removed from a note in discussion' do - before do - travel_to(1.minute.from_now) do - award_emoji.destroy! + context 'when an emoji is awarded to a note in discussion' do + before do + travel_to(1.minute.from_now) do + create(:award_emoji, awardable: first_note) + end end - end - it_behaves_like 'cache miss' do - let(:changed_notes) { [first_note, second_note] } + it_behaves_like 'cache miss' do + let(:changed_notes) { [first_note, second_note] } + end end - end - context 'when the diff note position changes' do - before do - # This replicates a position change wherein timestamps aren't updated - # which is why `Gitlab::Timeless.timeless` is utilized. This is the - # same approach being used in Discussions::UpdateDiffPositionService - # which is responsible for updating the positions of diff discussions - # when MR updates. - first_note.position = Gitlab::Diff::Position.new( - old_path: first_note.position.old_path, - new_path: first_note.position.new_path, - old_line: first_note.position.old_line, - new_line: first_note.position.new_line + 1, - diff_refs: first_note.position.diff_refs - ) - - Gitlab::Timeless.timeless(first_note, &:save) - end + context 'when an award emoji is removed from a note in discussion' do + before do + travel_to(1.minute.from_now) do + award_emoji.destroy! + end + end - it_behaves_like 'cache miss' do - let(:changed_notes) { [first_note, second_note] } + it_behaves_like 'cache miss' do + let(:changed_notes) { [first_note, second_note] } + end end - end - context 'when the HEAD diff note position changes' do - before do - # This replicates a DiffNotePosition change. This is the same approach - # being used in Discussions::CaptureDiffNotePositionService which is - # responsible for updating/creating DiffNotePosition of a diff discussions - # in relation to HEAD diff. - new_position = Gitlab::Diff::Position.new( - old_path: first_note.position.old_path, - new_path: first_note.position.new_path, - old_line: first_note.position.old_line, - new_line: first_note.position.new_line + 1, - diff_refs: first_note.position.diff_refs - ) - - DiffNotePosition.create_or_update_for( - first_note, - diff_type: :head, - position: new_position, - line_code: 'bd4b7bfff3a247ccf6e3371c41ec018a55230bcc_534_521' - ) - end + context 'when the diff note position changes' do + before do + # This replicates a position change wherein timestamps aren't updated + # which is why `Gitlab::Timeless.timeless` is utilized. This is the + # same approach being used in Discussions::UpdateDiffPositionService + # which is responsible for updating the positions of diff discussions + # when MR updates. + first_note.position = Gitlab::Diff::Position.new( + old_path: first_note.position.old_path, + new_path: first_note.position.new_path, + old_line: first_note.position.old_line, + new_line: first_note.position.new_line + 1, + diff_refs: first_note.position.diff_refs + ) + + Gitlab::Timeless.timeless(first_note, &:save) + end - it_behaves_like 'cache miss' do - let(:changed_notes) { [first_note, second_note] } + it_behaves_like 'cache miss' do + let(:changed_notes) { [first_note, second_note] } + end end - end - context 'when author detail changes' do - before do - author.update!(name: "#{author.name} (Updated)") - end + context 'when the HEAD diff note position changes' do + before do + # This replicates a DiffNotePosition change. This is the same approach + # being used in Discussions::CaptureDiffNotePositionService which is + # responsible for updating/creating DiffNotePosition of a diff discussions + # in relation to HEAD diff. + new_position = Gitlab::Diff::Position.new( + old_path: first_note.position.old_path, + new_path: first_note.position.new_path, + old_line: first_note.position.old_line, + new_line: first_note.position.new_line + 1, + diff_refs: first_note.position.diff_refs + ) + + DiffNotePosition.create_or_update_for( + first_note, + diff_type: :head, + position: new_position, + line_code: 'bd4b7bfff3a247ccf6e3371c41ec018a55230bcc_534_521' + ) + end - it_behaves_like 'cache miss' do - let(:changed_notes) { [first_note, second_note] } + it_behaves_like 'cache miss' do + let(:changed_notes) { [first_note, second_note] } + end end - end - context 'when author status changes' do - before do - Users::SetStatusService.new(author, message: "updated status").execute + context 'when author detail changes' do + before do + author.update!(name: "#{author.name} (Updated)") + end + + it_behaves_like 'cache miss' do + let(:changed_notes) { [first_note, second_note] } + end end - it_behaves_like 'cache miss' do - let(:changed_notes) { [first_note, second_note] } + context 'when author status changes' do + before do + Users::SetStatusService.new(author, message: "updated status").execute + end + + it_behaves_like 'cache miss' do + let(:changed_notes) { [first_note, second_note] } + end end - end - context 'when author role changes' do - before do - Members::UpdateService.new(owner, access_level: Gitlab::Access::GUEST).execute(author_membership) + context 'when author role changes' do + before do + Members::UpdateService.new(owner, access_level: Gitlab::Access::GUEST).execute(author_membership) + end + + it_behaves_like 'cache miss' do + let(:changed_notes) { [first_note, second_note] } + end end - it_behaves_like 'cache miss' do - let(:changed_notes) { [first_note, second_note] } + context 'when current_user role changes' do + before do + Members::UpdateService.new(owner, access_level: Gitlab::Access::GUEST).execute(project.member(user)) + end + + it_behaves_like 'cache miss' do + let(:changed_notes) { [first_note, second_note] } + end end end - context 'when current_user role changes' do + context 'when disabled_mr_discussions_redis_cache is disabled' do before do - Members::UpdateService.new(owner, access_level: Gitlab::Access::GUEST).execute(project.member(user)) + stub_feature_flags(disabled_mr_discussions_redis_cache: false) + send_request end - it_behaves_like 'cache miss' do - let(:changed_notes) { [first_note, second_note] } - end + it_behaves_like 'cache hit' end end end diff --git a/spec/requests/projects/settings/packages_and_registries_controller_spec.rb b/spec/requests/projects/settings/packages_and_registries_controller_spec.rb new file mode 100644 index 00000000000..6d8a152c769 --- /dev/null +++ b/spec/requests/projects/settings/packages_and_registries_controller_spec.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Projects::Settings::PackagesAndRegistriesController do + let_it_be(:user) { create(:user) } + let_it_be(:project, reload: true) { create(:project, namespace: user.namespace) } + + let(:container_registry_enabled) { true } + let(:container_registry_enabled_on_project) { ProjectFeature::ENABLED } + + before do + project.project_feature.update!(container_registry_access_level: container_registry_enabled_on_project) + project.container_expiration_policy.update!(enabled: true) + + stub_container_registry_config(enabled: container_registry_enabled) + end + + describe 'GET #cleanup_tags' do + subject { get cleanup_image_tags_namespace_project_settings_packages_and_registries_path(user.namespace, project) } + + context 'when user is unauthorized' do + let_it_be(:user) { create(:user) } + + before do + project.add_reporter(user) + sign_in(user) + subject + end + + it 'shows 404' do + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when user is authorized' do + let(:user) { project.creator } + + before do + sign_in(user) + subject + end + + it 'renders content' do + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:cleanup_tags) + end + + context 'when registry is disabled' do + let(:container_registry_enabled) { false } + + it 'shows 404' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when container registry is disabled on project' do + let(:container_registry_enabled_on_project) { ProjectFeature::DISABLED } + + it 'shows 404' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + end +end |