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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-02-20 16:49:51 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-02-20 16:49:51 +0300
commit71786ddc8e28fbd3cb3fcc4b3ff15e5962a1c82e (patch)
tree6a2d93ef3fb2d353bb7739e4b57e6541f51cdd71 /spec/controllers
parenta7253423e3403b8c08f8a161e5937e1488f5f407 (diff)
Add latest changes from gitlab-org/gitlab@15-9-stable-eev15.9.0-rc42
Diffstat (limited to 'spec/controllers')
-rw-r--r--spec/controllers/admin/application_settings/appearances_controller_spec.rb14
-rw-r--r--spec/controllers/admin/clusters_controller_spec.rb2
-rw-r--r--spec/controllers/admin/instance_review_controller_spec.rb2
-rw-r--r--spec/controllers/admin/runners_controller_spec.rb70
-rw-r--r--spec/controllers/admin/users_controller_spec.rb35
-rw-r--r--spec/controllers/autocomplete_controller_spec.rb10
-rw-r--r--spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb21
-rw-r--r--spec/controllers/concerns/product_analytics_tracking_spec.rb16
-rw-r--r--spec/controllers/concerns/send_file_upload_spec.rb15
-rw-r--r--spec/controllers/dashboard/projects_controller_spec.rb2
-rw-r--r--spec/controllers/dashboard_controller_spec.rb107
-rw-r--r--spec/controllers/explore/projects_controller_spec.rb2
-rw-r--r--spec/controllers/graphql_controller_spec.rb129
-rw-r--r--spec/controllers/groups/children_controller_spec.rb2
-rw-r--r--spec/controllers/groups/clusters_controller_spec.rb2
-rw-r--r--spec/controllers/groups/labels_controller_spec.rb2
-rw-r--r--spec/controllers/groups/runners_controller_spec.rb1
-rw-r--r--spec/controllers/groups_controller_spec.rb64
-rw-r--r--spec/controllers/import/bulk_imports_controller_spec.rb18
-rw-r--r--spec/controllers/import/github_controller_spec.rb58
-rw-r--r--spec/controllers/profiles/accounts_controller_spec.rb2
-rw-r--r--spec/controllers/profiles/two_factor_auths_controller_spec.rb133
-rw-r--r--spec/controllers/profiles_controller_spec.rb10
-rw-r--r--spec/controllers/projects/analytics/cycle_analytics/value_streams_controller_spec.rb14
-rw-r--r--spec/controllers/projects/artifacts_controller_spec.rb57
-rw-r--r--spec/controllers/projects/autocomplete_sources_controller_spec.rb160
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb14
-rw-r--r--spec/controllers/projects/clusters_controller_spec.rb2
-rw-r--r--spec/controllers/projects/commit_controller_spec.rb2
-rw-r--r--spec/controllers/projects/commits_controller_spec.rb2
-rw-r--r--spec/controllers/projects/environments_controller_spec.rb20
-rw-r--r--spec/controllers/projects/forks_controller_spec.rb2
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb66
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb56
-rw-r--r--spec/controllers/projects/labels_controller_spec.rb2
-rw-r--r--spec/controllers/projects/learn_gitlab_controller_spec.rb49
-rw-r--r--spec/controllers/projects/merge_requests/creations_controller_spec.rb2
-rw-r--r--spec/controllers/projects/merge_requests/diffs_controller_spec.rb36
-rw-r--r--spec/controllers/projects/merge_requests/drafts_controller_spec.rb102
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb146
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb2
-rw-r--r--spec/controllers/projects/pipeline_schedules_controller_spec.rb2
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb42
-rw-r--r--spec/controllers/projects/project_members_controller_spec.rb762
-rw-r--r--spec/controllers/projects/raw_controller_spec.rb48
-rw-r--r--spec/controllers/projects/refs_controller_spec.rb79
-rw-r--r--spec/controllers/projects/repositories_controller_spec.rb14
-rw-r--r--spec/controllers/projects/service_ping_controller_spec.rb77
-rw-r--r--spec/controllers/projects/settings/ci_cd_controller_spec.rb2
-rw-r--r--spec/controllers/projects/settings/repository_controller_spec.rb34
-rw-r--r--spec/controllers/projects_controller_spec.rb59
-rw-r--r--spec/controllers/registrations_controller_spec.rb18
-rw-r--r--spec/controllers/root_controller_spec.rb22
-rw-r--r--spec/controllers/search_controller_spec.rb5
-rw-r--r--spec/controllers/sessions_controller_spec.rb2
55 files changed, 1520 insertions, 1097 deletions
diff --git a/spec/controllers/admin/application_settings/appearances_controller_spec.rb b/spec/controllers/admin/application_settings/appearances_controller_spec.rb
index 78dce4558c3..f21c93e85d2 100644
--- a/spec/controllers/admin/application_settings/appearances_controller_spec.rb
+++ b/spec/controllers/admin/application_settings/appearances_controller_spec.rb
@@ -11,8 +11,10 @@ RSpec.describe Admin::ApplicationSettings::AppearancesController do
let(:create_params) do
{
title: 'Foo',
- pwa_short_name: 'F',
description: 'Bar',
+ pwa_name: 'GitLab PWA',
+ pwa_short_name: 'F',
+ pwa_description: 'This is GitLab as PWA',
header_message: header_message,
footer_message: footer_message
}
@@ -26,6 +28,11 @@ RSpec.describe Admin::ApplicationSettings::AppearancesController do
post :create, params: { appearance: create_params }
expect(Appearance.current).to have_attributes(
+ title: 'Foo',
+ description: 'Bar',
+ pwa_name: 'GitLab PWA',
+ pwa_short_name: 'F',
+ pwa_description: 'This is GitLab as PWA',
header_message: header_message,
footer_message: footer_message,
email_header_and_footer_enabled: false,
@@ -41,6 +48,11 @@ RSpec.describe Admin::ApplicationSettings::AppearancesController do
post :create, params: { appearance: create_params }
expect(Appearance.current).to have_attributes(
+ title: 'Foo',
+ description: 'Bar',
+ pwa_name: 'GitLab PWA',
+ pwa_short_name: 'F',
+ pwa_description: 'This is GitLab as PWA',
header_message: header_message,
footer_message: footer_message,
email_header_and_footer_enabled: true
diff --git a/spec/controllers/admin/clusters_controller_spec.rb b/spec/controllers/admin/clusters_controller_spec.rb
index 86a4ac61194..8e62aeed7d0 100644
--- a/spec/controllers/admin/clusters_controller_spec.rb
+++ b/spec/controllers/admin/clusters_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Admin::ClustersController do
+RSpec.describe Admin::ClustersController, feature_category: :kubernetes_management do
include AccessMatchersForController
include GoogleApi::CloudPlatformHelpers
diff --git a/spec/controllers/admin/instance_review_controller_spec.rb b/spec/controllers/admin/instance_review_controller_spec.rb
index 342562618b2..6eab135b3a6 100644
--- a/spec/controllers/admin/instance_review_controller_spec.rb
+++ b/spec/controllers/admin/instance_review_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Admin::InstanceReviewController do
+RSpec.describe Admin::InstanceReviewController, feature_category: :service_ping do
include UsageDataHelpers
let(:admin) { create(:admin) }
diff --git a/spec/controllers/admin/runners_controller_spec.rb b/spec/controllers/admin/runners_controller_spec.rb
index 6d58abb9d4d..a39a1f38a11 100644
--- a/spec/controllers/admin/runners_controller_spec.rb
+++ b/spec/controllers/admin/runners_controller_spec.rb
@@ -34,6 +34,33 @@ RSpec.describe Admin::RunnersController, feature_category: :runner_fleet do
end
end
+ describe '#new' do
+ context 'when create_runner_workflow is enabled' do
+ before do
+ stub_feature_flags(create_runner_workflow: true)
+ end
+
+ it 'renders a :new template' do
+ get :new
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:new)
+ end
+ end
+
+ context 'when create_runner_workflow is disabled' do
+ before do
+ stub_feature_flags(create_runner_workflow: false)
+ end
+
+ it 'returns :not_found' do
+ get :new
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
describe '#edit' do
render_views
@@ -105,49 +132,6 @@ RSpec.describe Admin::RunnersController, feature_category: :runner_fleet do
end
end
- describe '#destroy' do
- it 'destroys the runner' do
- expect_next_instance_of(Ci::Runners::UnregisterRunnerService, runner, user) do |service|
- expect(service).to receive(:execute).once.and_call_original
- end
-
- delete :destroy, params: { id: runner.id }
-
- expect(response).to have_gitlab_http_status(:found)
- expect(Ci::Runner.find_by(id: runner.id)).to be_nil
- end
- end
-
- describe '#resume' do
- it 'marks the runner as active and ticks the queue' do
- runner.update!(active: false)
-
- expect do
- post :resume, params: { id: runner.id }
- end.to change { runner.ensure_runner_queue_value }
-
- runner.reload
-
- expect(response).to have_gitlab_http_status(:found)
- expect(runner.active).to eq(true)
- end
- end
-
- describe '#pause' do
- it 'marks the runner as inactive and ticks the queue' do
- runner.update!(active: true)
-
- expect do
- post :pause, params: { id: runner.id }
- end.to change { runner.ensure_runner_queue_value }
-
- runner.reload
-
- expect(response).to have_gitlab_http_status(:found)
- expect(runner.active).to eq(false)
- end
- end
-
describe 'GET #runner_setup_scripts' do
it 'renders the setup scripts' do
get :runner_setup_scripts, params: { os: 'linux', arch: 'amd64' }
diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb
index eecb803fb1a..63e68118066 100644
--- a/spec/controllers/admin/users_controller_spec.rb
+++ b/spec/controllers/admin/users_controller_spec.rb
@@ -481,37 +481,22 @@ RSpec.describe Admin::UsersController do
end
describe 'PUT ban/:id', :aggregate_failures do
- context 'when ban_user_feature_flag is enabled' do
- it 'bans user' do
- put :ban, params: { id: user.username }
-
- expect(user.reload.banned?).to be_truthy
- expect(flash[:notice]).to eq _('Successfully banned')
- end
-
- context 'when unsuccessful' do
- let(:user) { create(:user, :blocked) }
+ it 'bans user' do
+ put :ban, params: { id: user.username }
- it 'does not ban user' do
- put :ban, params: { id: user.username }
-
- user.reload
- expect(user.banned?).to be_falsey
- expect(flash[:alert]).to eq _('Error occurred. User was not banned')
- end
- end
+ expect(user.reload.banned?).to be_truthy
+ expect(flash[:notice]).to eq _('Successfully banned')
end
- context 'when ban_user_feature_flag is not enabled' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
+ context 'when unsuccessful' do
+ let(:user) { create(:user, :blocked) }
- it 'does not ban user, renders 404' do
+ it 'does not ban user' do
put :ban, params: { id: user.username }
- expect(user.reload.banned?).to be_falsey
- expect(response).to have_gitlab_http_status(:not_found)
+ user.reload
+ expect(user.banned?).to be_falsey
+ expect(flash[:alert]).to eq _('Error occurred. User was not banned')
end
end
end
diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb
index e9b39d44e46..97729d181b1 100644
--- a/spec/controllers/autocomplete_controller_spec.rb
+++ b/spec/controllers/autocomplete_controller_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe AutocompleteController do
let(:project) { create(:project) }
let(:user) { project.first_owner }
- context 'GET users' do
+ context 'GET users', feature_category: :user_management do
let!(:user2) { create(:user) }
let!(:non_member) { create(:user) }
@@ -248,7 +248,7 @@ RSpec.describe AutocompleteController do
end
end
- context 'GET projects' do
+ context 'GET projects', feature_category: :projects do
let(:authorized_project) { create(:project) }
let(:authorized_search_project) { create(:project, name: 'rugged') }
@@ -339,7 +339,7 @@ RSpec.describe AutocompleteController do
end
end
- context 'GET award_emojis' do
+ context 'GET award_emojis', feature_category: :team_planning do
let(:user2) { create(:user) }
let!(:award_emoji1) { create_list(:award_emoji, 2, user: user, name: 'thumbsup') }
let!(:award_emoji2) { create_list(:award_emoji, 1, user: user, name: 'thumbsdown') }
@@ -377,7 +377,7 @@ RSpec.describe AutocompleteController do
end
end
- context 'GET deploy_keys_with_owners' do
+ context 'GET deploy_keys_with_owners', feature_category: :continuous_delivery do
let_it_be(:public_project) { create(:project, :public) }
let_it_be(:user) { create(:user) }
let_it_be(:deploy_key) { create(:deploy_key, user: user) }
@@ -451,7 +451,7 @@ RSpec.describe AutocompleteController do
end
end
- context 'Get merge_request_target_branches' do
+ context 'Get merge_request_target_branches', feature_category: :code_review_workflow do
let!(:merge_request) { create(:merge_request, source_project: project, target_branch: 'feature') }
context 'anonymous user' do
diff --git a/spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb b/spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb
new file mode 100644
index 00000000000..246119a8118
--- /dev/null
+++ b/spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Analytics::CycleAnalytics::ValueStreamActions, type: :controller,
+feature_category: :planning_analytics do
+ subject(:controller) do
+ Class.new(ApplicationController) do
+ include Analytics::CycleAnalytics::ValueStreamActions
+
+ def call_namespace
+ namespace
+ end
+ end
+ end
+
+ describe '#namespace' do
+ it 'raises NotImplementedError' do
+ expect { controller.new.call_namespace }.to raise_error(NotImplementedError)
+ end
+ end
+end
diff --git a/spec/controllers/concerns/product_analytics_tracking_spec.rb b/spec/controllers/concerns/product_analytics_tracking_spec.rb
index 28b79a10624..12b4065b89c 100644
--- a/spec/controllers/concerns/product_analytics_tracking_spec.rb
+++ b/spec/controllers/concerns/product_analytics_tracking_spec.rb
@@ -2,22 +2,24 @@
require "spec_helper"
-RSpec.describe ProductAnalyticsTracking, :snowplow do
+RSpec.describe ProductAnalyticsTracking, :snowplow, feature_category: :product_analytics do
include TrackingHelpers
include SnowplowHelpers
let(:user) { create(:user) }
+ let(:event_name) { 'an_event' }
let!(:group) { create(:group) }
before do
allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event)
+ stub_const("#{described_class}::MIGRATED_EVENTS", ['an_event'])
end
controller(ApplicationController) do
include ProductAnalyticsTracking
skip_before_action :authenticate_user!, only: :show
- track_event(:index, :show, name: 'g_analytics_valuestream', destinations: [:redis_hll, :snowplow],
+ track_event(:index, :show, name: 'an_event', destinations: [:redis_hll, :snowplow],
conditions: [:custom_condition_one?, :custom_condition_two?]) { |controller| controller.get_custom_id }
def index
@@ -53,16 +55,16 @@ RSpec.describe ProductAnalyticsTracking, :snowplow do
def expect_redis_hll_tracking
expect(Gitlab::UsageDataCounters::HLLRedisCounter).to have_received(:track_event)
- .with('g_analytics_valuestream', values: instance_of(String))
+ .with(event_name, values: instance_of(String))
end
def expect_snowplow_tracking(user)
- context = Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: 'g_analytics_valuestream')
+ context = Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name)
.to_context.to_json
expect_snowplow_event(
category: anything,
- action: 'g_analytics_valuestream',
+ action: event_name,
namespace: group,
user: user,
context: [context]
@@ -89,7 +91,9 @@ RSpec.describe ProductAnalyticsTracking, :snowplow do
context 'when FF is disabled' do
before do
- stub_feature_flags(route_hll_to_snowplow: false)
+ stub_const("#{described_class}::MIGRATED_EVENTS", [])
+ allow(Feature).to receive(:enabled?).and_call_original
+ allow(Feature).to receive(:enabled?).with('route_hll_to_snowplow', anything).and_return(false)
end
it 'doesnt track snowplow event' do
diff --git a/spec/controllers/concerns/send_file_upload_spec.rb b/spec/controllers/concerns/send_file_upload_spec.rb
index 0b24387483b..6acbff6e745 100644
--- a/spec/controllers/concerns/send_file_upload_spec.rb
+++ b/spec/controllers/concerns/send_file_upload_spec.rb
@@ -54,17 +54,18 @@ RSpec.describe SendFileUpload do
FileUtils.rm_f(temp_file)
end
- shared_examples 'handles image resize requests' do
+ shared_examples 'handles image resize requests' do |mount|
let(:headers) { double }
let(:image_requester) { build(:user) }
let(:image_owner) { build(:user) }
+ let(:width) { mount == :pwa_icon ? 192 : 64 }
let(:params) do
{ attachment: 'avatar.png' }
end
before do
allow(uploader).to receive(:image_safe_for_scaling?).and_return(true)
- allow(uploader).to receive(:mounted_as).and_return(:avatar)
+ allow(uploader).to receive(:mounted_as).and_return(mount)
allow(controller).to receive(:headers).and_return(headers)
# both of these are valid cases, depending on whether we are dealing with
@@ -99,11 +100,11 @@ RSpec.describe SendFileUpload do
context 'with valid width parameter' do
it 'renders OK with workhorse command header' do
expect(controller).not_to receive(:send_file)
- expect(controller).to receive(:params).at_least(:once).and_return(width: '64')
+ expect(controller).to receive(:params).at_least(:once).and_return(width: width.to_s)
expect(controller).to receive(:head).with(:ok)
expect(Gitlab::Workhorse).to receive(:send_scaled_image)
- .with(a_string_matching('^(/.+|https://.+)'), 64, 'image/png')
+ .with(a_string_matching('^(/.+|https://.+)'), width, 'image/png')
.and_return([Gitlab::Workhorse::SEND_DATA_HEADER, "send-scaled-img:faux"])
expect(headers).to receive(:store).with(Gitlab::Workhorse::SEND_DATA_HEADER, "send-scaled-img:faux")
@@ -168,7 +169,8 @@ RSpec.describe SendFileUpload do
subject
end
- it_behaves_like 'handles image resize requests'
+ it_behaves_like 'handles image resize requests', :avatar
+ it_behaves_like 'handles image resize requests', :pwa_icon
end
context 'with inline image' do
@@ -273,7 +275,8 @@ RSpec.describe SendFileUpload do
end
end
- it_behaves_like 'handles image resize requests'
+ it_behaves_like 'handles image resize requests', :avatar
+ it_behaves_like 'handles image resize requests', :pwa_icon
end
context 'when CDN-enabled remote file is used' do
diff --git a/spec/controllers/dashboard/projects_controller_spec.rb b/spec/controllers/dashboard/projects_controller_spec.rb
index b4a4ac56fce..e8ee146a13a 100644
--- a/spec/controllers/dashboard/projects_controller_spec.rb
+++ b/spec/controllers/dashboard/projects_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Dashboard::ProjectsController, :aggregate_failures do
+RSpec.describe Dashboard::ProjectsController, :aggregate_failures, feature_category: :projects do
include ExternalAuthorizationServiceHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/controllers/dashboard_controller_spec.rb b/spec/controllers/dashboard_controller_spec.rb
index ea12b0c5ad7..304e08f40bd 100644
--- a/spec/controllers/dashboard_controller_spec.rb
+++ b/spec/controllers/dashboard_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DashboardController do
+RSpec.describe DashboardController, feature_category: :code_review_workflow do
context 'signed in' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
@@ -46,6 +46,64 @@ RSpec.describe DashboardController do
describe 'GET merge requests' do
it_behaves_like 'issuables list meta-data', :merge_request, :merge_requests
it_behaves_like 'issuables requiring filter', :merge_requests
+
+ context 'when an ActiveRecord::QueryCanceled is raised' do
+ before do
+ allow_next_instance_of(Gitlab::IssuableMetadata) do |instance|
+ allow(instance).to receive(:data).and_raise(ActiveRecord::QueryCanceled)
+ end
+ end
+
+ it 'sets :search_timeout_occurred' do
+ get :merge_requests, params: { author_id: user.id }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(assigns(:search_timeout_occurred)).to eq(true)
+ end
+
+ context 'rendering views' do
+ render_views
+
+ it 'shows error message' do
+ get :merge_requests, params: { author_id: user.id }
+
+ expect(response.body).to have_content('Too many results to display. Edit your search or add a filter.')
+ end
+
+ it 'does not display MR counts in nav' do
+ get :merge_requests, params: { author_id: user.id }
+
+ expect(response.body).to have_content('Open Merged Closed All')
+ expect(response.body).not_to have_content('Open 0 Merged 0 Closed 0 All 0')
+ end
+ end
+
+ it 'logs the exception' do
+ expect(Gitlab::ErrorTracking).to receive(:track_exception).and_call_original
+
+ get :merge_requests, params: { author_id: user.id }
+ end
+ end
+
+ context 'when an ActiveRecord::QueryCanceled is not raised' do
+ it 'does not set :search_timeout_occurred' do
+ get :merge_requests, params: { author_id: user.id }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(assigns(:search_timeout_occurred)).to eq(nil)
+ end
+
+ context 'rendering views' do
+ render_views
+
+ it 'displays MR counts in nav' do
+ get :merge_requests, params: { author_id: user.id }
+
+ expect(response.body).to have_content('Open 0 Merged 0 Closed 0 All 0')
+ expect(response.body).not_to have_content('Open Merged Closed All')
+ end
+ end
+ end
end
end
@@ -53,9 +111,9 @@ RSpec.describe DashboardController do
include DesignManagementTestHelpers
render_views
- let(:user) { create(:user) }
- let(:project) { create(:project, :public, issues_access_level: ProjectFeature::PRIVATE) }
- let(:other_project) { create(:project, :public) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :public, issues_access_level: ProjectFeature::PRIVATE) }
+ let_it_be(:other_project) { create(:project, :public) }
before do
enable_design_management
@@ -76,22 +134,53 @@ RSpec.describe DashboardController do
other_project.add_developer(user)
end
- it 'returns count' do
- get :activity, params: { format: :json }
+ context 'without filter param' do
+ it 'returns only events of the user' do
+ get :activity, params: { format: :json }
+
+ expect(json_response['count']).to eq(3)
+ end
+ end
+
+ context 'with "projects" filter' do
+ it 'returns events of the user\'s projects' do
+ get :activity, params: { format: :json, filter: :projects }
- expect(json_response['count']).to eq(6)
+ expect(json_response['count']).to eq(6)
+ end
+ end
+
+ context 'with "followed" filter' do
+ let_it_be(:followed_user) { create(:user) }
+ let_it_be(:followed_user_private_project) { create(:project, :private) }
+ let_it_be(:followed_user_public_project) { create(:project, :public) }
+
+ before do
+ followed_user_private_project.add_developer(followed_user)
+ followed_user_public_project.add_developer(followed_user)
+ user.follow(followed_user)
+ create(:event, :created, project: followed_user_private_project, target: create(:issue),
+ author: followed_user)
+ create(:event, :created, project: followed_user_public_project, target: create(:issue), author: followed_user)
+ end
+
+ it 'returns public events of the user\'s followed users' do
+ get :activity, params: { format: :json, filter: :followed }
+
+ expect(json_response['count']).to eq(1)
+ end
end
end
context 'when user has no permission to see the event' do
it 'filters out invisible event' do
- get :activity, params: { format: :json }
+ get :activity, params: { format: :json, filter: :projects }
expect(json_response['html']).to include(_('No activities found'))
end
it 'filters out invisible event when calculating the count' do
- get :activity, params: { format: :json }
+ get :activity, params: { format: :json, filter: :projects }
expect(json_response['count']).to eq(0)
end
diff --git a/spec/controllers/explore/projects_controller_spec.rb b/spec/controllers/explore/projects_controller_spec.rb
index a79d9fa1276..c4f0feb21e2 100644
--- a/spec/controllers/explore/projects_controller_spec.rb
+++ b/spec/controllers/explore/projects_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Explore::ProjectsController do
+RSpec.describe Explore::ProjectsController, feature_category: :projects do
shared_examples 'explore projects' do
let(:expected_default_sort) { 'latest_activity_desc' }
diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb
index 75f281caa90..7aad67b01e8 100644
--- a/spec/controllers/graphql_controller_spec.rb
+++ b/spec/controllers/graphql_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GraphqlController do
+RSpec.describe GraphqlController, feature_category: :integrations do
include GraphqlHelpers
# two days is enough to make timezones irrelevant
@@ -329,11 +329,24 @@ RSpec.describe GraphqlController do
expect(assigns(:context)[:request]).to eq request
end
+
+ it 'sets `context[:remove_deprecated]` to false by default' do
+ post :execute
+
+ expect(assigns(:context)[:remove_deprecated]).to be false
+ end
+
+ it 'sets `context[:remove_deprecated]` to true when `remove_deprecated` param is truthy' do
+ post :execute, params: { remove_deprecated: '1' }
+
+ expect(assigns(:context)[:remove_deprecated]).to be true
+ end
end
describe 'Admin Mode' do
- let(:admin) { create(:admin) }
- let(:project) { create(:project) }
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:project) { create(:project) }
+
let(:graphql_query) { graphql_query_for('project', { 'fullPath' => project.full_path }, %w(id name)) }
before do
@@ -431,114 +444,4 @@ RSpec.describe GraphqlController do
expect(log_payload.dig(:exception_object)).to eq(exception)
end
end
-
- describe 'removal of deprecated items' do
- let(:mock_schema) do
- Class.new(GraphQL::Schema) do
- lazy_resolve ::Gitlab::Graphql::Lazy, :force
-
- query(Class.new(::Types::BaseObject) do
- graphql_name 'Query'
-
- field :foo, GraphQL::Types::Boolean,
- deprecated: { milestone: '0.1', reason: :renamed }
-
- field :bar, (Class.new(::Types::BaseEnum) do
- graphql_name 'BarEnum'
-
- value 'FOOBAR', value: 'foobar', deprecated: { milestone: '0.1', reason: :renamed }
- end)
-
- field :baz, GraphQL::Types::Boolean do
- argument :arg, String, required: false, deprecated: { milestone: '0.1', reason: :renamed }
- end
-
- def foo
- false
- end
-
- def bar
- 'foobar'
- end
-
- def baz(arg:)
- false
- end
- end)
- end
- end
-
- before do
- allow(GitlabSchema).to receive(:execute).and_wrap_original do |method, *args|
- mock_schema.execute(*args)
- end
- end
-
- context 'without `remove_deprecated` param' do
- let(:params) { { query: '{ foo bar baz(arg: "test") }' } }
-
- subject { post :execute, params: params }
-
- it "sets context's `remove_deprecated` value to false" do
- subject
-
- expect(assigns(:context)[:remove_deprecated]).to be false
- end
-
- it 'returns deprecated items in response' do
- subject
-
- expect(json_response).to include('data' => { 'foo' => false, 'bar' => 'FOOBAR', 'baz' => false })
- end
- end
-
- context 'with `remove_deprecated` param' do
- let(:params) { { remove_deprecated: 'true' } }
-
- subject { post :execute, params: params }
-
- it "sets context's `remove_deprecated` value to true" do
- subject
-
- expect(assigns(:context)[:remove_deprecated]).to be true
- end
-
- it 'does not allow deprecated field' do
- params[:query] = '{ foo }'
-
- subject
-
- expect(json_response).not_to include('data' => { 'foo' => false })
- expect(json_response).to include(
- 'errors' => include(a_hash_including('message' => /Field 'foo' doesn't exist on type 'Query'/))
- )
- end
-
- it 'does not allow deprecated enum value' do
- params[:query] = '{ bar }'
-
- subject
-
- expect(json_response).not_to include('data' => { 'bar' => 'FOOBAR' })
- expect(json_response).to include(
- 'errors' => include(
- a_hash_including(
- 'message' => /`Query.bar` returned `"foobar"` at `bar`, but this isn't a valid value for `BarEnum`/
- )
- )
- )
- end
-
- it 'does not allow deprecated argument' do
- params[:query] = '{ baz(arg: "test") }'
-
- subject
-
- expect(json_response).not_to include('data' => { 'bar' => 'FOOBAR' })
- expect(json_response).to include(
- 'errors' => include(a_hash_including('message' => /Field 'baz' doesn't accept argument 'arg'/))
- )
- end
- end
- end
end
diff --git a/spec/controllers/groups/children_controller_spec.rb b/spec/controllers/groups/children_controller_spec.rb
index f05551432fa..d0656ee47ce 100644
--- a/spec/controllers/groups/children_controller_spec.rb
+++ b/spec/controllers/groups/children_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::ChildrenController do
+RSpec.describe Groups::ChildrenController, feature_category: :subgroups do
include ExternalAuthorizationServiceHelpers
let(:group) { create(:group, :public) }
diff --git a/spec/controllers/groups/clusters_controller_spec.rb b/spec/controllers/groups/clusters_controller_spec.rb
index 46f507c34ba..01ea7101f2e 100644
--- a/spec/controllers/groups/clusters_controller_spec.rb
+++ b/spec/controllers/groups/clusters_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::ClustersController do
+RSpec.describe Groups::ClustersController, feature_category: :kubernetes_management do
include AccessMatchersForController
include GoogleApi::CloudPlatformHelpers
diff --git a/spec/controllers/groups/labels_controller_spec.rb b/spec/controllers/groups/labels_controller_spec.rb
index 0521c5e02a8..916b2cf10dd 100644
--- a/spec/controllers/groups/labels_controller_spec.rb
+++ b/spec/controllers/groups/labels_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::LabelsController do
+RSpec.describe Groups::LabelsController, feature_category: :team_planning do
let_it_be(:group) { create(:group) }
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, namespace: group) }
diff --git a/spec/controllers/groups/runners_controller_spec.rb b/spec/controllers/groups/runners_controller_spec.rb
index 93c1571bb6c..1a60f7d824e 100644
--- a/spec/controllers/groups/runners_controller_spec.rb
+++ b/spec/controllers/groups/runners_controller_spec.rb
@@ -30,7 +30,6 @@ RSpec.describe Groups::RunnersController, feature_category: :runner_fleet do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:index)
- expect(assigns(:group_runners_limited_count)).to be(2)
end
it 'tracks the event' do
diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb
index 22a406b3197..9184cd2263e 100644
--- a/spec/controllers/groups_controller_spec.rb
+++ b/spec/controllers/groups_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GroupsController, factory_default: :keep do
+RSpec.describe GroupsController, factory_default: :keep, feature_category: :code_review_workflow do
include ExternalAuthorizationServiceHelpers
include AdminModeHelper
@@ -552,6 +552,68 @@ RSpec.describe GroupsController, factory_default: :keep do
expect(assigns(:merge_requests)).to eq [merge_request_2, merge_request_1]
end
end
+
+ context 'rendering views' do
+ render_views
+
+ it 'displays MR counts in nav' do
+ get :merge_requests, params: { id: group.to_param }
+
+ expect(response.body).to have_content('Open 2 Merged 0 Closed 0 All 2')
+ expect(response.body).not_to have_content('Open Merged Closed All')
+ end
+
+ context 'when MergeRequestsFinder raises an exception' do
+ before do
+ allow_next_instance_of(MergeRequestsFinder) do |instance|
+ allow(instance).to receive(:count_by_state).and_raise(ActiveRecord::QueryCanceled)
+ end
+ end
+
+ it 'does not display MR counts in nav' do
+ get :merge_requests, params: { id: group.to_param }
+
+ expect(response.body).to have_content('Open Merged Closed All')
+ expect(response.body).not_to have_content('Open 0 Merged 0 Closed 0 All 0')
+ end
+ end
+ end
+
+ context 'when an ActiveRecord::QueryCanceled is raised' do
+ before do
+ allow_next_instance_of(Gitlab::IssuableMetadata) do |instance|
+ allow(instance).to receive(:data).and_raise(ActiveRecord::QueryCanceled)
+ end
+ end
+
+ it 'sets :search_timeout_occurred' do
+ get :merge_requests, params: { id: group.to_param }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(assigns(:search_timeout_occurred)).to eq(true)
+ end
+
+ it 'logs the exception' do
+ get :merge_requests, params: { id: group.to_param }
+ end
+
+ context 'rendering views' do
+ render_views
+
+ it 'shows error message' do
+ get :merge_requests, params: { id: group.to_param }
+
+ expect(response.body).to have_content('Too many results to display. Edit your search or add a filter.')
+ end
+
+ it 'does not display MR counts in nav' do
+ get :merge_requests, params: { id: group.to_param }
+
+ expect(response.body).to have_content('Open Merged Closed All')
+ expect(response.body).not_to have_content('Open 0 Merged 0 Closed 0 All 0')
+ end
+ end
+ end
end
describe 'DELETE #destroy' do
diff --git a/spec/controllers/import/bulk_imports_controller_spec.rb b/spec/controllers/import/bulk_imports_controller_spec.rb
index a0d5b576e74..a3992ae850e 100644
--- a/spec/controllers/import/bulk_imports_controller_spec.rb
+++ b/spec/controllers/import/bulk_imports_controller_spec.rb
@@ -9,14 +9,12 @@ RSpec.describe Import::BulkImportsController, feature_category: :importers do
stub_application_setting(bulk_import_enabled: true)
sign_in(user)
+
+ allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(false)
end
context 'when user is signed in' do
context 'when bulk_import feature flag is enabled' do
- before do
- stub_feature_flags(bulk_import: true)
- end
-
describe 'POST configure' do
before do
allow_next_instance_of(BulkImports::Clients::HTTP) do |instance|
@@ -400,6 +398,18 @@ RSpec.describe Import::BulkImportsController, feature_category: :importers do
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
end
+
+ context 'when request exceeds rate limits' do
+ it 'prevents user from starting a new migration' do
+ allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
+
+ post :create, params: { bulk_import: {} }
+
+ request
+
+ expect(response).to have_gitlab_http_status(:too_many_requests)
+ end
+ end
end
end
diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb
index c1a61a78d80..406a3604b23 100644
--- a/spec/controllers/import/github_controller_spec.rb
+++ b/spec/controllers/import/github_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Import::GithubController, feature_category: :import do
+RSpec.describe Import::GithubController, feature_category: :importers do
include ImportSpecHelper
let(:provider) { :github }
@@ -375,7 +375,9 @@ RSpec.describe Import::GithubController, feature_category: :import do
it_behaves_like 'a GitHub-ish import controller: GET realtime_changes'
it 'includes stats in response' do
- create(:project, import_type: provider, namespace: user.namespace, import_status: :finished, import_source: 'example/repo')
+ project = create(:project, import_type: provider, namespace: user.namespace, import_status: :finished, import_source: 'example/repo')
+
+ ::Gitlab::GithubImport::ObjectCounter.increment(project, :issue, :imported, value: 8)
get :realtime_changes
@@ -417,4 +419,56 @@ RSpec.describe Import::GithubController, feature_category: :import do
end
end
end
+
+ describe 'POST cancel_all' do
+ context 'when import is in progress' do
+ it 'returns success' do
+ project = create(:project, :import_scheduled, namespace: user.namespace, import_type: 'github', import_url: 'https://fake.url')
+ project2 = create(:project, :import_started, namespace: user.namespace, import_type: 'github', import_url: 'https://fake2.url')
+
+ expect(Import::Github::CancelProjectImportService)
+ .to receive(:new).with(project, user)
+ .and_return(double(execute: { status: :success, project: project }))
+
+ expect(Import::Github::CancelProjectImportService)
+ .to receive(:new).with(project2, user)
+ .and_return(double(execute: { status: :bad_request, message: 'The import cannot be canceled because it is finished' }))
+
+ post :cancel_all
+
+ expect(json_response).to eq([
+ {
+ 'id' => project.id,
+ 'status' => 'success'
+ },
+ {
+ 'id' => project2.id,
+ 'status' => 'bad_request',
+ 'error' => 'The import cannot be canceled because it is finished'
+ }
+ ])
+ end
+ end
+
+ context 'when there is no imports in progress' do
+ it 'returns an empty array' do
+ create(:project, :import_finished, namespace: user.namespace, import_type: 'github', import_url: 'https://fake.url')
+
+ post :cancel_all
+
+ expect(json_response).to eq([])
+ end
+ end
+
+ context 'when there is no projects created by user' do
+ it 'returns an empty array' do
+ other_user_project = create(:project, :import_started, import_type: 'github', import_url: 'https://fake.url')
+
+ post :cancel_all
+
+ expect(json_response).to eq([])
+ expect(other_user_project.import_status).to eq('started')
+ end
+ end
+ end
end
diff --git a/spec/controllers/profiles/accounts_controller_spec.rb b/spec/controllers/profiles/accounts_controller_spec.rb
index 1b4b67eeaff..ba349768b0f 100644
--- a/spec/controllers/profiles/accounts_controller_spec.rb
+++ b/spec/controllers/profiles/accounts_controller_spec.rb
@@ -31,7 +31,7 @@ RSpec.describe Profiles::AccountsController do
end
end
- [:twitter, :facebook, :google_oauth2, :gitlab, :github, :bitbucket, :crowd, :auth0, :authentiq, :dingtalk, :alicloud].each do |provider|
+ [:twitter, :facebook, :google_oauth2, :gitlab, :github, :bitbucket, :crowd, :auth0, :dingtalk, :alicloud].each do |provider|
describe "#{provider} provider" do
let(:user) { create(:omniauth_user, provider: provider.to_s) }
diff --git a/spec/controllers/profiles/two_factor_auths_controller_spec.rb b/spec/controllers/profiles/two_factor_auths_controller_spec.rb
index 1dd564427d3..7d7cdededdb 100644
--- a/spec/controllers/profiles/two_factor_auths_controller_spec.rb
+++ b/spec/controllers/profiles/two_factor_auths_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Profiles::TwoFactorAuthsController do
+RSpec.describe Profiles::TwoFactorAuthsController, feature_category: :authentication_and_authorization do
before do
# `user` should be defined within the action-specific describe blocks
sign_in(user)
@@ -31,7 +31,7 @@ RSpec.describe Profiles::TwoFactorAuthsController do
shared_examples 'user must enter a valid current password' do
let(:current_password) { '123' }
- let(:error_message) { { message: _('You must provide a valid current password') } }
+ let(:error_message) { { message: _('You must provide a valid current password.') } }
it 'requires the current password', :aggregate_failures do
go
@@ -154,7 +154,7 @@ RSpec.describe Profiles::TwoFactorAuthsController do
context 'with valid pin' do
before do
- expect(user).to receive(:validate_and_consume_otp!).with(pin).and_return(true)
+ allow(user).to receive(:validate_and_consume_otp!).with(pin).and_return(true)
end
it 'enables 2fa for the user' do
@@ -187,6 +187,64 @@ RSpec.describe Profiles::TwoFactorAuthsController do
it 'renders create' do
go
expect(response).to render_template(:create)
+ expect(user.otp_backup_codes?).to be_eql(true)
+ end
+
+ it 'do not create new backup codes if exists' do
+ expect(user).to receive(:otp_backup_codes?).and_return(true)
+ go
+ expect(response).to redirect_to(profile_two_factor_auth_path)
+ end
+
+ it 'calls to delete other sessions when backup codes already exist' do
+ expect(user).to receive(:otp_backup_codes?).and_return(true)
+ expect(ActiveSession).to receive(:destroy_all_but_current)
+ go
+ end
+
+ context 'when webauthn_without_totp flag is disabled' do
+ before do
+ stub_feature_flags(webauthn_without_totp: false)
+ expect(user).to receive(:validate_and_consume_otp!).with(pin).and_return(true)
+ end
+
+ it 'enables 2fa for the user' do
+ go
+
+ user.reload
+ expect(user).to be_two_factor_enabled
+ end
+
+ it 'presents plaintext codes for the user to save' do
+ expect(user).to receive(:generate_otp_backup_codes!).and_return(%w(a b c))
+
+ go
+
+ expect(assigns[:codes]).to match_array %w(a b c)
+ end
+
+ it 'calls to delete other sessions' do
+ expect(ActiveSession).to receive(:destroy_all_but_current)
+
+ go
+ end
+
+ it 'dismisses the `TWO_FACTOR_AUTH_RECOVERY_SETTINGS_CHECK` callout' do
+ expect(controller.helpers).to receive(:dismiss_two_factor_auth_recovery_settings_check)
+
+ go
+ end
+
+ it 'renders create' do
+ go
+ expect(response).to render_template(:create)
+ end
+
+ it 'renders create even if backup code already exists' do
+ expect(user).to receive(:otp_backup_codes?).and_return(true)
+ go
+ expect(response).to render_template(:create)
+ end
end
end
@@ -254,6 +312,75 @@ RSpec.describe Profiles::TwoFactorAuthsController do
end
end
+ describe 'POST create_webauthn' do
+ let_it_be_with_reload(:user) { create(:user) }
+ let(:client) { WebAuthn::FakeClient.new('http://localhost', encoding: :base64) }
+ let(:credential) { create_credential(client: client, rp_id: request.host) }
+
+ let(:params) { { device_registration: { name: 'touch id', device_response: device_response } } } # rubocop:disable Rails/SaveBang
+
+ let(:params_with_password) { { device_registration: { name: 'touch id', device_response: device_response }, current_password: user.password } } # rubocop:disable Rails/SaveBang
+
+ before do
+ session[:challenge] = challenge
+ end
+
+ def go
+ post :create_webauthn, params: params
+ end
+
+ def challenge
+ @_challenge ||= begin
+ options_for_create = WebAuthn::Credential.options_for_create(
+ user: { id: user.webauthn_xid, name: user.username },
+ authenticator_selection: { user_verification: 'discouraged' },
+ rp: { name: 'GitLab' }
+ )
+ options_for_create.challenge
+ end
+ end
+
+ def device_response
+ client.create(challenge: challenge).to_json # rubocop:disable Rails/SaveBang
+ end
+
+ it 'update failed_attempts when proper password is not given' do
+ go
+ expect(user.failed_attempts).to be_eql(1)
+ end
+
+ context "when valid password is given" do
+ it "registers and render OTP backup codes" do
+ post :create_webauthn, params: params_with_password
+ expect(user.otp_backup_codes).not_to be_empty
+ expect(flash[:notice]).to match(/Your WebAuthn device was registered!/)
+ end
+
+ it 'registers and redirects back if user is already having backup codes' do
+ expect(user).to receive(:otp_backup_codes?).and_return(true)
+ post :create_webauthn, params: params_with_password
+ expect(response).to redirect_to(profile_two_factor_auth_path)
+ expect(flash[:notice]).to match(/Your WebAuthn device was registered!/)
+ end
+ end
+
+ context "when the feature flag 'webauthn_without_totp' is disabled" do
+ before do
+ stub_feature_flags(webauthn_without_totp: false)
+ session[:challenge] = challenge
+ end
+
+ let(:params) { { device_registration: { name: 'touch id', device_response: device_response } } } # rubocop:disable Rails/SaveBang
+
+ it "does not validate the current_password" do
+ go
+
+ expect(flash[:notice]).to match(/Your WebAuthn device was registered!/)
+ expect(response).to redirect_to(profile_two_factor_auth_path)
+ end
+ end
+ end
+
describe 'DELETE destroy' do
def go
delete :destroy, params: { current_password: current_password }
diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb
index aa92ff6be33..daf0f36c28b 100644
--- a/spec/controllers/profiles_controller_spec.rb
+++ b/spec/controllers/profiles_controller_spec.rb
@@ -126,6 +126,16 @@ RSpec.describe ProfilesController, :request_store do
expect(user.reload.pronunciation).to eq(pronunciation)
expect(response).to have_gitlab_http_status(:found)
end
+
+ it 'allows updating user specified Discord User ID', :aggregate_failures do
+ discord_user_id = '1234567890123456789'
+ sign_in(user)
+
+ put :update, params: { user: { discord: discord_user_id } }
+
+ expect(user.reload.discord).to eq(discord_user_id)
+ expect(response).to have_gitlab_http_status(:found)
+ end
end
describe 'GET audit_log' do
diff --git a/spec/controllers/projects/analytics/cycle_analytics/value_streams_controller_spec.rb b/spec/controllers/projects/analytics/cycle_analytics/value_streams_controller_spec.rb
index 5b434eb2011..a3a86138f18 100644
--- a/spec/controllers/projects/analytics/cycle_analytics/value_streams_controller_spec.rb
+++ b/spec/controllers/projects/analytics/cycle_analytics/value_streams_controller_spec.rb
@@ -30,6 +30,20 @@ RSpec.describe Projects::Analytics::CycleAnalytics::ValueStreamsController do
expect(json_response.first['name']).to eq('default')
end
+
+ # testing the authorize method within ValueStreamActions
+ context 'when issues and merge requests are disabled' do
+ it 'renders 404' do
+ project.project_feature.update!(
+ issues_access_level: ProjectFeature::DISABLED,
+ merge_requests_access_level: ProjectFeature::DISABLED
+ )
+
+ get :index, params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
end
context 'when user is not member of the project' do
diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb
index 3d12926c07a..32cd10d9805 100644
--- a/spec/controllers/projects/artifacts_controller_spec.rb
+++ b/spec/controllers/projects/artifacts_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ArtifactsController do
+RSpec.describe Projects::ArtifactsController, feature_category: :build_artifacts do
include RepoHelpers
let(:user) { project.first_owner }
@@ -37,23 +37,6 @@ RSpec.describe Projects::ArtifactsController do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template('projects/artifacts/index')
-
- app = Nokogiri::HTML.parse(response.body).at_css('div#js-artifact-management')
-
- expect(app.attributes['data-project-path'].value).to eq(project.full_path)
- expect(app.attributes['data-can-destroy-artifacts'].value).to eq('true')
- end
-
- describe 'when user does not have permission to delete artifacts' do
- let(:user) { create(:user) }
-
- it 'passes false to the artifacts app' do
- subject
-
- app = Nokogiri::HTML.parse(response.body).at_css('div#js-artifact-management')
-
- expect(app.attributes['data-can-destroy-artifacts'].value).to eq('false')
- end
end
end
@@ -127,7 +110,7 @@ RSpec.describe Projects::ArtifactsController do
end
context 'when no file type is supplied' do
- let(:filename) { job.artifacts_file.filename }
+ let(:filename) { job.job_artifacts_archive.filename }
it 'sends the artifacts file' do
expect(controller).to receive(:send_file)
@@ -141,6 +124,38 @@ RSpec.describe Projects::ArtifactsController do
end
end
+ context 'when artifact is set as private' do
+ let(:filename) { job.artifacts_file.filename }
+
+ before do
+ job.job_artifacts.update_all(accessibility: 'private')
+ end
+
+ context 'and user is not authoirized' do
+ let(:user) { create(:user) }
+
+ it 'returns forbidden' do
+ download_artifact(file_type: 'archive')
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'and user has access to project' do
+ it 'downloads' do
+ expect(controller).to receive(:send_file)
+ .with(
+ job.artifacts_file.file.path,
+ hash_including(disposition: 'attachment', filename: filename)).and_call_original
+
+ download_artifact(file_type: 'archive')
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.headers['Content-Disposition']).to eq(%Q(attachment; filename="#{filename}"; filename*=UTF-8''#{filename}))
+ end
+ end
+ end
+
context 'when a file type is supplied' do
context 'when an invalid file type is supplied' do
let(:file_type) { 'invalid' }
@@ -255,10 +270,14 @@ RSpec.describe Projects::ArtifactsController do
end
context 'when the user has update_build permissions' do
+ let(:filename) { job.job_artifacts_trace.file.filename }
+
it 'sends the trace' do
download_artifact(file_type: file_type)
expect(response).to have_gitlab_http_status(:ok)
+ expect(response.headers['Content-Disposition'])
+ .to eq(%Q(attachment; filename="#{filename}"; filename*=UTF-8''#{filename}))
end
end
end
diff --git a/spec/controllers/projects/autocomplete_sources_controller_spec.rb b/spec/controllers/projects/autocomplete_sources_controller_spec.rb
index 7077aae6b45..70178083e71 100644
--- a/spec/controllers/projects/autocomplete_sources_controller_spec.rb
+++ b/spec/controllers/projects/autocomplete_sources_controller_spec.rb
@@ -4,10 +4,14 @@ require 'spec_helper'
RSpec.describe Projects::AutocompleteSourcesController do
let_it_be(:group, reload: true) { create(:group) }
+ let_it_be(:private_group) { create(:group, :private) }
let_it_be(:project) { create(:project, namespace: group) }
let_it_be(:public_project) { create(:project, :public, group: group) }
let_it_be(:development) { create(:label, project: project, name: 'Development') }
- let_it_be(:issue) { create(:labeled_issue, project: project, labels: [development]) }
+ let_it_be(:private_issue) { create(:labeled_issue, project: project, labels: [development]) }
+ let_it_be(:private_work_item) { create(:work_item, project: project) }
+ let_it_be(:issue) { create(:labeled_issue, project: public_project, labels: [development]) }
+ let_it_be(:work_item) { create(:work_item, project: public_project, id: 1, iid: 100) }
let_it_be(:user) { create(:user) }
def members_by_username(username)
@@ -22,7 +26,7 @@ RSpec.describe Projects::AutocompleteSourcesController do
context 'with a public project' do
shared_examples 'issuable commands' do
it 'returns empty array when no user logged in' do
- get :commands, format: :json, params: { namespace_id: group.path, project_id: public_project.path, type: issuable_type, type_id: issuable_iid }
+ get :commands, format: :json, params: { namespace_id: group.path, project_id: public_project.path, type: issuable_type }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq([])
@@ -52,6 +56,13 @@ RSpec.describe Projects::AutocompleteSourcesController do
it_behaves_like 'issuable commands'
end
+ context 'with work items' do
+ let(:issuable_type) { work_item.class.name }
+ let(:issuable_iid) { work_item.iid }
+
+ it_behaves_like 'issuable commands'
+ end
+
context 'with merge request' do
let(:merge_request) { create(:merge_request, target_project: public_project, source_project: public_project) }
let(:issuable_type) { merge_request.class.name }
@@ -68,24 +79,49 @@ RSpec.describe Projects::AutocompleteSourcesController do
sign_in(user)
end
- it 'raises an error when no target type specified' do
- expect { get :labels, format: :json, params: { namespace_id: group.path, project_id: project.path } }
- .to raise_error(ActionController::ParameterMissing)
+ shared_examples 'label commands' do
+ it 'raises an error when no target type specified' do
+ expect { get :labels, format: :json, params: { namespace_id: group.path, project_id: project.path } }
+ .to raise_error(ActionController::ParameterMissing)
+ end
+
+ it 'returns an array of labels' do
+ get :labels, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issuable_type }
+
+ expect(json_response).to be_a(Array)
+ expect(json_response.count).to eq(1)
+ expect(json_response[0]['title']).to eq('Development')
+ end
+ end
+
+ context 'with issues' do
+ let(:issuable_type) { issue.class.name }
+ let(:issuable_iid) { issue.iid }
+
+ it_behaves_like 'label commands'
end
- it 'returns an array of labels' do
- get :labels, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name, type_id: issue.id }
+ context 'with work items' do
+ let(:issuable_type) { work_item.class.name }
+ let(:issuable_iid) { work_item.iid }
- expect(json_response).to be_a(Array)
- expect(json_response.count).to eq(1)
- expect(json_response[0]['title']).to eq('Development')
+ it_behaves_like 'label commands'
end
end
describe 'GET members' do
+ let_it_be(:invited_private_member) { create(:user) }
+ let_it_be(:issue) { create(:labeled_issue, project: public_project, labels: [development], author: user) }
+ let_it_be(:work_item) { create(:work_item, project: public_project, author: user) }
+
+ before_all do
+ create(:project_group_link, group: private_group, project: public_project)
+ group.add_owner(user)
+ private_group.add_developer(invited_private_member)
+ end
+
context 'when logged in' do
before do
- group.add_owner(user)
sign_in(user)
end
@@ -94,42 +130,88 @@ RSpec.describe Projects::AutocompleteSourcesController do
.to raise_error(ActionController::ParameterMissing)
end
- it 'returns an array of member object' do
- get :members, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name, type_id: issue.id }
+ shared_examples 'all members are returned' do
+ it 'returns an array of member object' do
+ get :members, format: :json, params: { namespace_id: group.path, project_id: public_project.path, type: issuable_type }
+
+ expect(members_by_username('all').symbolize_keys).to include(
+ username: 'all',
+ name: 'All Project and Group Members',
+ count: 2)
+
+ expect(members_by_username(group.full_path).symbolize_keys).to include(
+ type: group.class.name,
+ name: group.full_name,
+ avatar_url: group.avatar_url,
+ count: 1)
+
+ expect(members_by_username(user.username).symbolize_keys).to include(
+ type: user.class.name,
+ name: user.name,
+ avatar_url: user.avatar_url)
+
+ expect(members_by_username(invited_private_member.username).symbolize_keys).to include(
+ type: invited_private_member.class.name,
+ name: invited_private_member.name,
+ avatar_url: invited_private_member.avatar_url)
+ end
+ end
- expect(members_by_username('all').symbolize_keys).to include(
- username: 'all',
- name: 'All Project and Group Members',
- count: 1)
+ context 'with issue' do
+ let(:issuable_type) { issue.class.name }
- expect(members_by_username(group.full_path).symbolize_keys).to include(
- type: group.class.name,
- name: group.full_name,
- avatar_url: group.avatar_url,
- count: 1)
+ it_behaves_like 'all members are returned'
+ end
- expect(members_by_username(user.username).symbolize_keys).to include(
- type: user.class.name,
- name: user.name,
- avatar_url: user.avatar_url)
+ context 'with work item' do
+ let(:issuable_type) { work_item.class.name }
+
+ it_behaves_like 'all members are returned'
end
end
context 'when anonymous' do
- it 'redirects to login page' do
- get :members, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name, type_id: issue.id }
+ shared_examples 'private project is inaccessible' do
+ it 'redirects to login page for private project' do
+ get :members, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issuable_type }
- expect(response).to redirect_to new_user_session_path
+ expect(response).to redirect_to new_user_session_path
+ end
end
- context 'with public project' do
- it 'returns no members' do
- get :members, format: :json, params: { namespace_id: group.path, project_id: public_project.path, type: issue.class.name, type_id: issue.id }
+ shared_examples 'only public members are returned for public project' do
+ it 'only returns public members' do
+ get :members, format: :json, params: { namespace_id: group.path, project_id: public_project.path, type: issuable_type }
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to be_a(Array)
- expect(json_response.count).to eq(1)
- expect(json_response.first['count']).to eq(0)
+ expect(members_by_username('all').symbolize_keys).to include(
+ username: 'all',
+ name: 'All Project and Group Members',
+ count: 1)
+
+ expect(members_by_username(user.username).symbolize_keys).to include(
+ type: user.class.name,
+ name: user.name,
+ avatar_url: user.avatar_url)
+ end
+ end
+
+ context 'with issue' do
+ it_behaves_like 'private project is inaccessible' do
+ let(:issuable_type) { private_issue.class.name }
+ end
+
+ it_behaves_like 'only public members are returned for public project' do
+ let(:issuable_type) { issue.class.name }
+ end
+ end
+
+ context 'with work item' do
+ it_behaves_like 'private project is inaccessible' do
+ let(:issuable_type) { private_work_item.class.name }
+ end
+
+ it_behaves_like 'only public members are returned for public project' do
+ let(:issuable_type) { work_item.class.name }
end
end
end
@@ -184,7 +266,7 @@ RSpec.describe Projects::AutocompleteSourcesController do
it 'lists contacts' do
group.add_developer(user)
- get :contacts, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name, type_id: issue.id }
+ get :contacts, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name }
emails = json_response.map { |contact_data| contact_data["email"] }
expect(emails).to match_array([contact_1.email, contact_2.email])
@@ -193,7 +275,7 @@ RSpec.describe Projects::AutocompleteSourcesController do
context 'when a user can not read contacts' do
it 'renders 404' do
- get :contacts, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name, type_id: issue.id }
+ get :contacts, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name }
expect(response).to have_gitlab_http_status(:not_found)
end
@@ -204,7 +286,7 @@ RSpec.describe Projects::AutocompleteSourcesController do
it 'renders 404' do
group.add_developer(user)
- get :contacts, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name, type_id: issue.id }
+ get :contacts, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name }
expect(response).to have_gitlab_http_status(:not_found)
end
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index ed11d5936b0..dcde22c1fd6 100644
--- a/spec/controllers/projects/branches_controller_spec.rb
+++ b/spec/controllers/projects/branches_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::BranchesController do
+RSpec.describe Projects::BranchesController, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:developer) { create(:user) }
@@ -676,6 +676,18 @@ RSpec.describe Projects::BranchesController do
end
end
+ context 'when state is not supported' do
+ before do
+ get :index, format: :html, params: {
+ namespace_id: project.namespace, project_id: project, state: 'unknown'
+ }
+ end
+
+ it 'returns 404 page' do
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
context 'sorting', :aggregate_failures do
let(:sort) { 'name_asc' }
diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb
index 894f0f8354d..a4f7c92f5cd 100644
--- a/spec/controllers/projects/clusters_controller_spec.rb
+++ b/spec/controllers/projects/clusters_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ClustersController do
+RSpec.describe Projects::ClustersController, feature_category: :kubernetes_management do
include AccessMatchersForController
include GoogleApi::CloudPlatformHelpers
include KubernetesHelpers
diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb
index edb07bbdce6..8d3939d8133 100644
--- a/spec/controllers/projects/commit_controller_spec.rb
+++ b/spec/controllers/projects/commit_controller_spec.rb
@@ -36,6 +36,7 @@ RSpec.describe Projects::CommitController do
go(id: commit.id)
expect(response).to be_ok
+ expect(assigns(:ref)).to eq commit.id
end
context 'when a pipeline job is running' do
@@ -57,6 +58,7 @@ RSpec.describe Projects::CommitController do
go(id: commit.id.reverse)
expect(response).to be_not_found
+ expect(assigns(:ref)).to be_nil
end
end
diff --git a/spec/controllers/projects/commits_controller_spec.rb b/spec/controllers/projects/commits_controller_spec.rb
index 26d4725656f..67aa82dacbb 100644
--- a/spec/controllers/projects/commits_controller_spec.rb
+++ b/spec/controllers/projects/commits_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::CommitsController do
+RSpec.describe Projects::CommitsController, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb
index dddefbac163..169fed1ab17 100644
--- a/spec/controllers/projects/environments_controller_spec.rb
+++ b/spec/controllers/projects/environments_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::EnvironmentsController do
+RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_delivery do
include MetricsDashboardHelpers
include KubernetesHelpers
@@ -103,6 +103,24 @@ RSpec.describe Projects::EnvironmentsController do
expect(json_response['stopped_count']).to eq 1
end
+ context 'can access stop stale environments feature' do
+ it 'maintainers can access the feature' do
+ get :index, params: environment_params(format: :json)
+
+ expect(json_response['can_stop_stale_environments']).to be_truthy
+ end
+
+ context 'when user is a reporter' do
+ let(:user) { reporter }
+
+ it 'reporters cannot access the feature' do
+ get :index, params: environment_params(format: :json)
+
+ expect(json_response['can_stop_stale_environments']).to be_falsey
+ end
+ end
+ end
+
context 'when enable_environments_search_within_folder FF is disabled' do
before do
stub_feature_flags(enable_environments_search_within_folder: false)
diff --git a/spec/controllers/projects/forks_controller_spec.rb b/spec/controllers/projects/forks_controller_spec.rb
index 962ef93dc72..25c722173c1 100644
--- a/spec/controllers/projects/forks_controller_spec.rb
+++ b/spec/controllers/projects/forks_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ForksController do
+RSpec.describe Projects::ForksController, feature_category: :source_code_management do
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
let(:forked_project) { Projects::ForkService.new(project, user, name: 'Some name').execute }
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 31e297e5773..9c272872a73 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::IssuesController do
+RSpec.describe Projects::IssuesController, feature_category: :team_planning do
include ProjectForksHelper
include_context 'includes Spam constants'
@@ -647,9 +647,8 @@ RSpec.describe Projects::IssuesController do
end
end
- context 'when allow_possible_spam feature flag is false' do
+ context 'when allow_possible_spam application setting is false' do
before do
- stub_feature_flags(allow_possible_spam: false)
expect(controller).to(receive(:spam_action_response_fields).with(issue)) do
spam_action_response_fields
end
@@ -662,7 +661,11 @@ RSpec.describe Projects::IssuesController do
end
end
- context 'when allow_possible_spam feature flag is true' do
+ context 'when allow_possible_spam application setting is true' do
+ before do
+ stub_application_setting(allow_possible_spam: true)
+ end
+
it 'updates the issue' do
subject
@@ -887,11 +890,7 @@ RSpec.describe Projects::IssuesController do
end
end
- context 'when allow_possible_spam feature flag is false' do
- before do
- stub_feature_flags(allow_possible_spam: false)
- end
-
+ context 'when allow_possible_spam application setting is false' do
it 'rejects an issue recognized as spam' do
expect { update_issue }.not_to change { issue.reload.title }
end
@@ -925,7 +924,11 @@ RSpec.describe Projects::IssuesController do
end
end
- context 'when allow_possible_spam feature flag is true' do
+ context 'when allow_possible_spam application setting is true' do
+ before do
+ stub_application_setting(allow_possible_spam: true)
+ end
+
it 'updates the issue recognized as spam' do
expect { update_issue }.to change { issue.reload.title }
end
@@ -1234,8 +1237,6 @@ RSpec.describe Projects::IssuesController do
context 'when SpamVerdictService allows the issue' do
before do
- stub_feature_flags(allow_possible_spam: false)
-
expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service|
expect(verdict_service).to receive(:execute).and_return(ALLOW)
end
@@ -1258,11 +1259,7 @@ RSpec.describe Projects::IssuesController do
post_new_issue(title: 'Spam Title', description: 'Spam lives here')
end
- context 'when allow_possible_spam feature flag is false' do
- before do
- stub_feature_flags(allow_possible_spam: false)
- end
-
+ context 'when allow_possible_spam application setting is false' do
it 'rejects an issue recognized as spam' do
expect { post_spam_issue }.not_to change(Issue, :count)
end
@@ -1283,7 +1280,11 @@ RSpec.describe Projects::IssuesController do
end
end
- context 'when allow_possible_spam feature flag is true' do
+ context 'when allow_possible_spam application setting is true' do
+ before do
+ stub_application_setting(allow_possible_spam: true)
+ end
+
it 'creates an issue recognized as spam' do
expect { post_spam_issue }.to change(Issue, :count)
end
@@ -1377,13 +1378,13 @@ RSpec.describe Projects::IssuesController do
end
context 'when issue creation limits imposed' do
- it 'prevents from creating more issues', :request_store do
- post_new_issue
-
- expect { post_new_issue }
- .to change { Gitlab::GitalyClient.get_request_count }.by(1) # creates 1 projects and 0 issues
+ before do
+ project.add_developer(user)
+ sign_in(user)
+ end
- post_new_issue
+ it 'prevents from creating more issues', :request_store do
+ 2.times { post_new_issue_in_project }
expect(response.body).to eq(_('This endpoint has been requested too many times. Try again later.'))
expect(response).to have_gitlab_http_status(:too_many_requests)
@@ -1402,16 +1403,15 @@ RSpec.describe Projects::IssuesController do
expect(Gitlab::AuthLogger).to receive(:error).with(attributes).once
- project.add_developer(user)
- sign_in(user)
+ 2.times { post_new_issue_in_project }
+ end
- 2.times do
- post :create, params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- issue: { title: 'Title', description: 'Description' }
- }
- end
+ def post_new_issue_in_project
+ post :create, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ issue: { title: 'Title', description: 'Description' }
+ }
end
end
end
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index 3dc89365530..8fb9623c21a 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
+RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, feature_category: :continuous_integration do
include ApiHelpers
include HttpIOHelpers
@@ -809,14 +809,48 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
sign_in(user)
end
+ context 'when job is not retryable' do
+ context 'and the job is a bridge' do
+ let(:job) { create(:ci_bridge, :failed, :reached_max_descendant_pipelines_depth, pipeline: pipeline) }
+
+ it 'renders unprocessable_entity' do
+ post_retry
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ end
+ end
+
+ context 'and the job is a build' do
+ let(:job) { create(:ci_build, :deployment_rejected, pipeline: pipeline) }
+
+ it 'renders unprocessable_entity' do
+ post_retry
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ end
+ end
+ end
+
context 'when job is retryable' do
- let(:job) { create(:ci_build, :retryable, pipeline: pipeline) }
+ context 'and the job is a bridge' do
+ let(:job) { create(:ci_bridge, :retryable, pipeline: pipeline) }
- it 'redirects to the retried job page' do
- post_retry
+ it 'responds :ok' do
+ post_retry
- expect(response).to have_gitlab_http_status(:found)
- expect(response).to redirect_to(namespace_project_job_path(id: Ci::Build.last.id))
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'and the job is a build' do
+ let(:job) { create(:ci_build, :retryable, pipeline: pipeline) }
+
+ it 'redirects to the retried job page' do
+ post_retry
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(response).to redirect_to(namespace_project_job_path(id: Ci::Build.last.id))
+ end
end
shared_examples_for 'retried job has the same attributes' do
@@ -847,16 +881,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
end
end
- context 'when job is not retryable' do
- let(:job) { create(:ci_build, pipeline: pipeline) }
-
- it 'renders unprocessable_entity' do
- post_retry
-
- expect(response).to have_gitlab_http_status(:unprocessable_entity)
- end
- end
-
def post_retry
post :retry, params: {
namespace_id: project.namespace,
diff --git a/spec/controllers/projects/labels_controller_spec.rb b/spec/controllers/projects/labels_controller_spec.rb
index dfa6ed639b6..98982856d6c 100644
--- a/spec/controllers/projects/labels_controller_spec.rb
+++ b/spec/controllers/projects/labels_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::LabelsController do
+RSpec.describe Projects::LabelsController, feature_category: :team_planning do
let_it_be(:group) { create(:group) }
let_it_be(:project, reload: true) { create(:project, namespace: group) }
let_it_be(:user) { create(:user) }
diff --git a/spec/controllers/projects/learn_gitlab_controller_spec.rb b/spec/controllers/projects/learn_gitlab_controller_spec.rb
deleted file mode 100644
index a93da82d948..00000000000
--- a/spec/controllers/projects/learn_gitlab_controller_spec.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Projects::LearnGitlabController do
- describe 'GET #index' do
- let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project, namespace: create(:group)) }
-
- let(:learn_gitlab_enabled) { true }
- let(:params) { { namespace_id: project.namespace.to_param, project_id: project } }
-
- subject(:action) { get :index, params: params }
-
- before do
- project.namespace.add_owner(user)
- allow(controller.helpers).to receive(:learn_gitlab_enabled?).and_return(learn_gitlab_enabled)
- end
-
- context 'unauthenticated user' do
- it { is_expected.to have_gitlab_http_status(:redirect) }
- end
-
- context 'authenticated user' do
- before do
- sign_in(user)
- end
-
- it { is_expected.to render_template(:index) }
-
- context 'learn_gitlab experiment not enabled' do
- let(:learn_gitlab_enabled) { false }
-
- it { is_expected.to have_gitlab_http_status(:not_found) }
- end
-
- context 'with invite_for_help_continuous_onboarding experiment' do
- it 'tracks the assignment', :experiment do
- stub_experiments(invite_for_help_continuous_onboarding: true)
-
- expect(experiment(:invite_for_help_continuous_onboarding))
- .to track(:assignment).with_context(namespace: project.namespace).on_next_instance
-
- action
- end
- end
- end
- end
-end
diff --git a/spec/controllers/projects/merge_requests/creations_controller_spec.rb b/spec/controllers/projects/merge_requests/creations_controller_spec.rb
index 7db708e0e78..3d4a884587f 100644
--- a/spec/controllers/projects/merge_requests/creations_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/creations_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::MergeRequests::CreationsController do
+RSpec.describe Projects::MergeRequests::CreationsController, feature_category: :code_review_workflow do
let(:project) { create(:project, :repository) }
let(:user) { project.first_owner }
let(:fork_project) { create(:forked_project_with_submodules) }
diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
index 4de724fd6d6..23a33d7e0b1 100644
--- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::MergeRequests::DiffsController do
+RSpec.describe Projects::MergeRequests::DiffsController, feature_category: :code_review_workflow do
include ProjectForksHelper
include TrackingHelpers
@@ -610,5 +610,39 @@ RSpec.describe Projects::MergeRequests::DiffsController do
go
end
end
+
+ context 'when ck param is present' do
+ let(:cache_key) { merge_request.merge_head_diff.id }
+
+ before do
+ create(:merge_request_diff, :merge_head, merge_request: merge_request)
+ end
+
+ it 'sets Cache-Control with max-age' do
+ go(ck: cache_key, diff_head: true)
+
+ expect(response.headers['Cache-Control']).to eq('max-age=86400, private')
+ end
+
+ context 'when diffs_batch_cache_with_max_age feature flag is disabled' do
+ before do
+ stub_feature_flags(diffs_batch_cache_with_max_age: false)
+ end
+
+ it 'does not set Cache-Control with max-age' do
+ go(ck: cache_key, diff_head: true)
+
+ expect(response.headers['Cache-Control']).not_to eq('max-age=86400, private')
+ end
+ end
+
+ context 'when not rendering merge head diff' do
+ it 'does not set Cache-Control with max-age' do
+ go(ck: cache_key, diff_head: false)
+
+ expect(response.headers['Cache-Control']).not_to eq('max-age=86400, private')
+ end
+ end
+ end
end
end
diff --git a/spec/controllers/projects/merge_requests/drafts_controller_spec.rb b/spec/controllers/projects/merge_requests/drafts_controller_spec.rb
index 182d654aaa8..39482938a8b 100644
--- a/spec/controllers/projects/merge_requests/drafts_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/drafts_controller_spec.rb
@@ -388,104 +388,72 @@ RSpec.describe Projects::MergeRequests::DraftsController do
context 'publish with note' do
before do
+ allow(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .to receive(:track_submit_review_comment)
+
create(:draft_note, merge_request: merge_request, author: user)
end
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(mr_review_submit_comment: false)
- end
-
- it 'does not create note' do
- post :publish, params: params.merge!(note: 'Hello world')
+ it 'creates note' do
+ post :publish, params: params.merge!(note: 'Hello world')
- expect(merge_request.notes.reload.size).to be(1)
- end
+ expect(merge_request.notes.reload.size).to be(2)
end
- context 'when feature flag is enabled' do
- before do
- allow(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
- .to receive(:track_submit_review_comment)
- end
-
- it 'creates note' do
- post :publish, params: params.merge!(note: 'Hello world')
-
- expect(merge_request.notes.reload.size).to be(2)
- end
+ it 'does not create note when note param is empty' do
+ post :publish, params: params.merge!(note: '')
- it 'does not create note when note param is empty' do
- post :publish, params: params.merge!(note: '')
-
- expect(merge_request.notes.reload.size).to be(1)
- end
+ expect(merge_request.notes.reload.size).to be(1)
+ end
- it 'tracks merge request activity' do
- post :publish, params: params.merge!(note: 'Hello world')
+ it 'tracks merge request activity' do
+ post :publish, params: params.merge!(note: 'Hello world')
- expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
- .to have_received(:track_submit_review_comment).with(user: user)
- end
+ expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .to have_received(:track_submit_review_comment).with(user: user)
end
end
context 'approve merge request' do
before do
+ allow(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .to receive(:track_submit_review_approve)
+
create(:draft_note, merge_request: merge_request, author: user)
end
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(mr_review_submit_comment: false)
- end
+ it 'approves merge request' do
+ post :publish, params: params.merge!(approve: true)
- it 'does not approve' do
- post :publish, params: params.merge!(approve: true)
-
- expect(merge_request.approvals.reload.size).to be(0)
- end
+ expect(merge_request.approvals.reload.size).to be(1)
end
- context 'when feature flag is enabled' do
- before do
- allow(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
- .to receive(:track_submit_review_approve)
- end
+ it 'does not approve merge request' do
+ post :publish, params: params.merge!(approve: false)
- it 'approves merge request' do
- post :publish, params: params.merge!(approve: true)
+ expect(merge_request.approvals.reload.size).to be(0)
+ end
- expect(merge_request.approvals.reload.size).to be(1)
- end
+ it 'tracks merge request activity' do
+ post :publish, params: params.merge!(approve: true)
- it 'does not approve merge request' do
- post :publish, params: params.merge!(approve: false)
+ expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .to have_received(:track_submit_review_approve).with(user: user)
+ end
- expect(merge_request.approvals.reload.size).to be(0)
+ context 'when merge request is already approved by user' do
+ before do
+ create(:approval, merge_request: merge_request, user: user)
end
- it 'tracks merge request activity' do
+ it 'does return 200' do
post :publish, params: params.merge!(approve: true)
+ expect(response).to have_gitlab_http_status(:ok)
+
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
.to have_received(:track_submit_review_approve).with(user: user)
end
-
- context 'when merge request is already approved by user' do
- before do
- create(:approval, merge_request: merge_request, user: user)
- end
-
- it 'does return 200' do
- post :publish, params: params.merge!(approve: true)
-
- expect(response).to have_gitlab_http_status(:ok)
-
- expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
- .to have_received(:track_submit_review_approve).with(user: user)
- end
- end
end
end
end
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 095775b0ddd..ceb3f803db5 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -68,6 +68,72 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review
end
end
+ context 'when add_prepared_state_to_mr feature flag on' do
+ before do
+ stub_feature_flags(add_prepared_state_to_mr: true)
+ end
+
+ context 'when the merge request is not prepared' do
+ before do
+ merge_request.update!(prepared_at: nil, created_at: 10.minutes.ago)
+ end
+
+ it 'prepares the merge request' do
+ expect(NewMergeRequestWorker).to receive(:perform_async)
+
+ go
+ end
+
+ context 'when the merge request was created less than 5 minutes ago' do
+ it 'does not prepare the merge request again' do
+ travel_to(4.minutes.from_now) do
+ merge_request.update!(created_at: Time.current - 4.minutes)
+
+ expect(NewMergeRequestWorker).not_to receive(:perform_async)
+
+ go
+ end
+ end
+ end
+
+ context 'when the merge request was created 5 minutes ago' do
+ it 'prepares the merge request' do
+ travel_to(6.minutes.from_now) do
+ merge_request.update!(created_at: Time.current - 6.minutes)
+
+ expect(NewMergeRequestWorker).to receive(:perform_async)
+
+ go
+ end
+ end
+ end
+ end
+
+ context 'when the merge request is prepared' do
+ before do
+ merge_request.update!(prepared_at: Time.current, created_at: 10.minutes.ago)
+ end
+
+ it 'prepares the merge request' do
+ expect(NewMergeRequestWorker).not_to receive(:perform_async)
+
+ go
+ end
+ end
+ end
+
+ context 'when add_prepared_state_to_mr feature flag is off' do
+ before do
+ stub_feature_flags(add_prepared_state_to_mr: false)
+ end
+
+ it 'does not prepare the merge request again' do
+ expect(NewMergeRequestWorker).not_to receive(:perform_async)
+
+ go
+ end
+ end
+
describe 'as html' do
it 'sets the endpoint_metadata_url' do
go
@@ -82,6 +148,61 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review
w: '0'))
end
+ context 'when merge_head diff is present' do
+ before do
+ create(:merge_request_diff, :merge_head, merge_request: merge_request)
+ end
+
+ it 'sets the endpoint_diff_batch_url with ck' do
+ go
+
+ expect(assigns["endpoint_diff_batch_url"]).to eq(
+ diffs_batch_project_json_merge_request_path(
+ project,
+ merge_request,
+ 'json',
+ diff_head: true,
+ view: 'inline',
+ w: '0',
+ page: '0',
+ per_page: '5',
+ ck: merge_request.merge_head_diff.id))
+ end
+
+ it 'sets diffs_batch_cache_key' do
+ go
+
+ expect(assigns['diffs_batch_cache_key']).to eq(merge_request.merge_head_diff.id)
+ end
+
+ context 'when diffs_batch_cache_with_max_age feature flag is disabled' do
+ before do
+ stub_feature_flags(diffs_batch_cache_with_max_age: false)
+ end
+
+ it 'sets the endpoint_diff_batch_url without ck param' do
+ go
+
+ expect(assigns['endpoint_diff_batch_url']).to eq(
+ diffs_batch_project_json_merge_request_path(
+ project,
+ merge_request,
+ 'json',
+ diff_head: true,
+ view: 'inline',
+ w: '0',
+ page: '0',
+ per_page: '5'))
+ end
+
+ it 'does not set diffs_batch_cache_key' do
+ go
+
+ expect(assigns['diffs_batch_cache_key']).to be_nil
+ end
+ end
+ end
+
context 'when diff files were cleaned' do
render_views
@@ -335,15 +456,6 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review
end
end
end
-
- it_behaves_like 'issuable list with anonymous search disabled' do
- let(:params) { { namespace_id: project.namespace, project_id: project } }
-
- before do
- sign_out(user)
- project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
- end
- end
end
describe 'PUT update' do
@@ -1856,18 +1968,26 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review
}
end
- it 'shows a flash message on success' do
+ it 'displays an flash error message on fail' do
+ allow(MergeRequests::AssignIssuesService).to receive(:new).and_return(double(execute: { count: 0 }))
+
post_assign_issues
- expect(flash[:notice]).to eq '2 issues have been assigned to you'
+ expect(flash[:alert]).to eq _('Failed to assign you issues related to the merge request.')
end
- it 'correctly pluralizes flash message on success' do
+ it 'shows a flash message on success' do
issue2.assignees = [user]
post_assign_issues
- expect(flash[:notice]).to eq '1 issue has been assigned to you'
+ expect(flash[:notice]).to eq n_("An issue has been assigned to you.", "%d issues have been assigned to you.", 1)
+ end
+
+ it 'correctly pluralizes flash message on success' do
+ post_assign_issues
+
+ expect(flash[:notice]).to eq n_("An issue has been assigned to you.", "%d issues have been assigned to you.", 2)
end
it 'calls MergeRequests::AssignIssuesService' do
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index 0afd2e10ea2..23b0b58158f 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::NotesController do
+RSpec.describe Projects::NotesController, type: :controller, feature_category: :team_planning do
include ProjectForksHelper
let(:user) { create(:user) }
diff --git a/spec/controllers/projects/pipeline_schedules_controller_spec.rb b/spec/controllers/projects/pipeline_schedules_controller_spec.rb
index 358b98621a5..a628c1ab230 100644
--- a/spec/controllers/projects/pipeline_schedules_controller_spec.rb
+++ b/spec/controllers/projects/pipeline_schedules_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::PipelineSchedulesController do
+RSpec.describe Projects::PipelineSchedulesController, feature_category: :continuous_integration do
include AccessMatchersForController
let_it_be(:user) { create(:user) }
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index 3d1d28945f7..4e0c098ad81 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::PipelinesController do
+RSpec.describe Projects::PipelinesController, feature_category: :continuous_integration do
include ApiHelpers
let_it_be(:user) { create(:user) }
@@ -52,21 +52,6 @@ RSpec.describe Projects::PipelinesController do
expect(stages.count).to eq 3
end
end
-
- it 'does not execute N+1 queries', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/345470' do
- get_pipelines_index_json
-
- control_count = ActiveRecord::QueryRecorder.new do
- get_pipelines_index_json
- end.count
-
- create_all_pipeline_types
-
- # There appears to be one extra query for Pipelines#has_warnings? for some reason
- expect { get_pipelines_index_json }.not_to exceed_query_limit(control_count + 1)
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['pipelines'].count).to eq 12
- end
end
it 'does not include coverage data for the pipelines' do
@@ -83,14 +68,7 @@ RSpec.describe Projects::PipelinesController do
check_pipeline_response(returned: 2, all: 6)
end
- context 'when performing gitaly calls', :request_store do
- before do
- # To prevent double writes / fallback read due to MultiStore which is failing the `Gitlab::GitalyClient
- # .get_request_count` expectation.
- stub_feature_flags(use_primary_store_as_default_for_repository_cache: false)
- stub_feature_flags(use_primary_and_secondary_stores_for_repository_cache: false)
- end
-
+ context 'when performing gitaly calls', :request_store, :use_null_store_as_repository_cache do
it 'limits the Gitaly requests' do
# Isolate from test preparation (Repository#exists? is also cached in RequestStore)
RequestStore.end!
@@ -1355,8 +1333,8 @@ RSpec.describe Projects::PipelinesController do
.and_return(service)
end
- context 'when sending a valid sha' do
- let(:sha) { 'master' }
+ context 'when sending a valid ref' do
+ let(:ref) { 'master' }
let(:ci_config) do
{
variables: {
@@ -1381,8 +1359,8 @@ RSpec.describe Projects::PipelinesController do
end
end
- context 'when sending an invalid sha' do
- let(:sha) { 'invalid-sha' }
+ context 'when sending an invalid ref' do
+ let(:ref) { 'invalid-ref' }
before do
synchronous_reactive_cache(service)
@@ -1397,7 +1375,7 @@ RSpec.describe Projects::PipelinesController do
end
context 'when sending an invalid config' do
- let(:sha) { 'master' }
+ let(:ref) { 'master' }
let(:ci_config) do
{
variables: {
@@ -1423,7 +1401,7 @@ RSpec.describe Projects::PipelinesController do
end
context 'when the cache is empty' do
- let(:sha) { 'master' }
+ let(:ref) { 'master' }
let(:ci_config) do
{
variables: {
@@ -1446,7 +1424,7 @@ RSpec.describe Projects::PipelinesController do
context 'when project uses external project ci config' do
let(:other_project) { create(:project, :custom_repo, files: other_project_files) }
let(:other_project_files) { { '.gitlab-ci.yml' => YAML.dump(other_project_ci_config) } }
- let(:sha) { 'master' }
+ let(:ref) { 'master' }
let(:other_project_ci_config) do
{
@@ -1479,7 +1457,7 @@ RSpec.describe Projects::PipelinesController do
def get_config_variables
get :config_variables, params: { namespace_id: project.namespace,
project_id: project,
- sha: sha },
+ sha: ref },
format: :json
end
end
diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb
index fb27fe58cd9..ab33195eb83 100644
--- a/spec/controllers/projects/project_members_controller_spec.rb
+++ b/spec/controllers/projects/project_members_controller_spec.rb
@@ -8,183 +8,168 @@ RSpec.describe Projects::ProjectMembersController do
let_it_be(:sub_group) { create(:group, parent: group) }
let_it_be(:project, reload: true) { create(:project, :public) }
- before do
- travel_to DateTime.new(2019, 4, 1)
- end
+ shared_examples_for 'controller actions' do
+ before do
+ travel_to DateTime.new(2019, 4, 1)
+ end
- after do
- travel_back
- end
+ after do
+ travel_back
+ end
- describe 'GET index' do
- it 'has the project_members address with a 200 status code' do
- get :index, params: { namespace_id: project.namespace, project_id: project }
+ describe 'GET index' do
+ it 'has the project_members address with a 200 status code' do
+ get :index, params: { namespace_id: project.namespace, project_id: project }
- expect(response).to have_gitlab_http_status(:ok)
- end
+ expect(response).to have_gitlab_http_status(:ok)
+ end
- context 'project members' do
- context 'when project belongs to group' do
- let_it_be(:user_in_group) { create(:user) }
- let_it_be(:project_in_group) { create(:project, :public, group: group) }
+ context 'project members' do
+ context 'when project belongs to group' do
+ let_it_be(:user_in_group) { create(:user) }
+ let_it_be(:project_in_group) { create(:project, :public, group: group) }
- before do
- group.add_owner(user_in_group)
- project_in_group.add_maintainer(user)
- sign_in(user)
- end
+ before do
+ group.add_owner(user_in_group)
+ project_in_group.add_maintainer(user)
+ sign_in(user)
+ end
- it 'lists inherited project members by default' do
- get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group }
+ it 'lists inherited project members by default' do
+ get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group }
- expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user.id, user_in_group.id)
- end
+ expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user.id, user_in_group.id)
+ end
- it 'lists direct project members only' do
- get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group, with_inherited_permissions: 'exclude' }
+ it 'lists direct project members only' do
+ get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group, with_inherited_permissions: 'exclude' }
- expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user.id)
- end
+ expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user.id)
+ end
- it 'lists inherited project members only' do
- get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group, with_inherited_permissions: 'only' }
+ it 'lists inherited project members only' do
+ get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group, with_inherited_permissions: 'only' }
- expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user_in_group.id)
+ expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user_in_group.id)
+ end
end
- end
- context 'when project belongs to a sub-group' do
- let_it_be(:user_in_group) { create(:user) }
- let_it_be(:project_in_group) { create(:project, :public, group: sub_group) }
+ context 'when project belongs to a sub-group' do
+ let_it_be(:user_in_group) { create(:user) }
+ let_it_be(:project_in_group) { create(:project, :public, group: sub_group) }
- before do
- group.add_owner(user_in_group)
- project_in_group.add_maintainer(user)
- sign_in(user)
- end
+ before do
+ group.add_owner(user_in_group)
+ project_in_group.add_maintainer(user)
+ sign_in(user)
+ end
- it 'lists inherited project members by default' do
- get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group }
+ it 'lists inherited project members by default' do
+ get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group }
- expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user.id, user_in_group.id)
- end
+ expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user.id, user_in_group.id)
+ end
- it 'lists direct project members only' do
- get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group, with_inherited_permissions: 'exclude' }
+ it 'lists direct project members only' do
+ get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group, with_inherited_permissions: 'exclude' }
- expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user.id)
- end
+ expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user.id)
+ end
- it 'lists inherited project members only' do
- get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group, with_inherited_permissions: 'only' }
+ it 'lists inherited project members only' do
+ get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group, with_inherited_permissions: 'only' }
- expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user_in_group.id)
+ expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user_in_group.id)
+ end
end
- end
- context 'when invited project members are present' do
- let!(:invited_member) { create(:project_member, :invited, project: project) }
+ context 'when invited project members are present' do
+ let!(:invited_member) { create(:project_member, :invited, project: project) }
- before do
- project.add_maintainer(user)
- sign_in(user)
- end
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ end
- it 'excludes the invited members from project members list' do
- get :index, params: { namespace_id: project.namespace, project_id: project }
+ it 'excludes the invited members from project members list' do
+ get :index, params: { namespace_id: project.namespace, project_id: project }
- expect(assigns(:project_members).map(&:invite_email)).not_to contain_exactly(invited_member.invite_email)
+ expect(assigns(:project_members).map(&:invite_email)).not_to contain_exactly(invited_member.invite_email)
+ end
end
end
- end
-
- context 'invited members' do
- let_it_be(:invited_member) { create(:project_member, :invited, project: project) }
- before do
- sign_in(user)
- end
+ context 'invited members' do
+ let_it_be(:invited_member) { create(:project_member, :invited, project: project) }
- context 'when user has `admin_project_member` permissions' do
before do
- project.add_maintainer(user)
+ sign_in(user)
end
- it 'lists invited members' do
- get :index, params: { namespace_id: project.namespace, project_id: project }
+ context 'when user has `admin_project_member` permissions' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'lists invited members' do
+ get :index, params: { namespace_id: project.namespace, project_id: project }
- expect(assigns(:invited_members).map(&:invite_email)).to contain_exactly(invited_member.invite_email)
+ expect(assigns(:invited_members).map(&:invite_email)).to contain_exactly(invited_member.invite_email)
+ end
end
- end
- context 'when user does not have `admin_project_member` permissions' do
- it 'does not list invited members' do
- get :index, params: { namespace_id: project.namespace, project_id: project }
+ context 'when user does not have `admin_project_member` permissions' do
+ it 'does not list invited members' do
+ get :index, params: { namespace_id: project.namespace, project_id: project }
- expect(assigns(:invited_members)).to be_nil
+ expect(assigns(:invited_members)).to be_nil
+ end
end
end
- end
- context 'access requests' do
- let_it_be(:access_requester_user) { create(:user) }
-
- before do
- project.request_access(access_requester_user)
- sign_in(user)
- end
+ context 'access requests' do
+ let_it_be(:access_requester_user) { create(:user) }
- context 'when user has `admin_project_member` permissions' do
before do
- project.add_maintainer(user)
+ project.request_access(access_requester_user)
+ sign_in(user)
end
- it 'lists access requests' do
- get :index, params: { namespace_id: project.namespace, project_id: project }
+ context 'when user has `admin_project_member` permissions' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'lists access requests' do
+ get :index, params: { namespace_id: project.namespace, project_id: project }
- expect(assigns(:requesters).map(&:user_id)).to contain_exactly(access_requester_user.id)
+ expect(assigns(:requesters).map(&:user_id)).to contain_exactly(access_requester_user.id)
+ end
end
- end
- context 'when user does not have `admin_project_member` permissions' do
- it 'does not list access requests' do
- get :index, params: { namespace_id: project.namespace, project_id: project }
+ context 'when user does not have `admin_project_member` permissions' do
+ it 'does not list access requests' do
+ get :index, params: { namespace_id: project.namespace, project_id: project }
- expect(assigns(:requesters)).to be_nil
+ expect(assigns(:requesters)).to be_nil
+ end
end
end
end
- end
-
- describe 'PUT update' do
- let_it_be(:requester) { create(:project_member, :access_request, project: project) }
-
- before do
- project.add_maintainer(user)
- sign_in(user)
- end
- context 'access level' do
- Gitlab::Access.options.each do |label, value|
- it "can change the access level to #{label}" do
- params = {
- project_member: { access_level: value },
- namespace_id: project.namespace,
- project_id: project,
- id: requester
- }
+ describe 'PUT update' do
+ let_it_be(:requester) { create(:project_member, :access_request, project: project) }
- put :update, params: params, xhr: true
-
- expect(requester.reload.human_access).to eq(label)
- end
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
end
- describe 'managing project direct owners' do
- context 'when a Maintainer tries to elevate another user to OWNER' do
- it 'does not allow the operation' do
+ context 'access level' do
+ Gitlab::Access.options.each do |label, value|
+ it "can change the access level to #{label}" do
params = {
- project_member: { access_level: Gitlab::Access::OWNER },
+ project_member: { access_level: value },
namespace_id: project.namespace,
project_id: project,
id: requester
@@ -192,368 +177,395 @@ RSpec.describe Projects::ProjectMembersController do
put :update, params: params, xhr: true
- expect(response).to have_gitlab_http_status(:forbidden)
+ expect(requester.reload.human_access).to eq(label)
end
end
- context 'when a user with OWNER access tries to elevate another user to OWNER' do
- # inherited owner role via personal project association
- let(:user) { project.first_owner }
+ describe 'managing project direct owners' do
+ context 'when a Maintainer tries to elevate another user to OWNER' do
+ it 'does not allow the operation' do
+ params = {
+ project_member: { access_level: Gitlab::Access::OWNER },
+ namespace_id: project.namespace,
+ project_id: project,
+ id: requester
+ }
- before do
- sign_in(user)
+ put :update, params: params, xhr: true
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
end
- it 'returns success' do
- params = {
- project_member: { access_level: Gitlab::Access::OWNER },
- namespace_id: project.namespace,
- project_id: project,
- id: requester
- }
+ context 'when a user with OWNER access tries to elevate another user to OWNER' do
+ # inherited owner role via personal project association
+ let(:user) { project.first_owner }
- put :update, params: params, xhr: true
+ before do
+ sign_in(user)
+ end
+
+ it 'returns success' do
+ params = {
+ project_member: { access_level: Gitlab::Access::OWNER },
+ namespace_id: project.namespace,
+ project_id: project,
+ id: requester
+ }
+
+ put :update, params: params, xhr: true
- expect(response).to have_gitlab_http_status(:ok)
- expect(requester.reload.access_level).to eq(Gitlab::Access::OWNER)
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(requester.reload.access_level).to eq(Gitlab::Access::OWNER)
+ end
end
end
end
- end
- context 'access expiry date' do
- subject do
- put :update, xhr: true, params: {
- project_member: {
- expires_at: expires_at
- },
- namespace_id: project.namespace,
- project_id: project,
- id: requester
- }
- end
+ context 'access expiry date' do
+ subject do
+ put :update, xhr: true, params: {
+ project_member: {
+ expires_at: expires_at
+ },
+ namespace_id: project.namespace,
+ project_id: project,
+ id: requester
+ }
+ end
- context 'when set to a date in the past' do
- let(:expires_at) { 2.days.ago }
+ context 'when set to a date in the past' do
+ let(:expires_at) { 2.days.ago }
- it 'does not update the member' do
- subject
+ it 'does not update the member' do
+ subject
- expect(requester.reload.expires_at).not_to eq(expires_at.to_date)
- end
+ expect(requester.reload.expires_at).not_to eq(expires_at.to_date)
+ end
- it 'returns error status' do
- subject
+ it 'returns error status' do
+ subject
- expect(response).to have_gitlab_http_status(:unprocessable_entity)
- end
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ end
- it 'returns error message' do
- subject
+ it 'returns error message' do
+ subject
- expect(json_response).to eq({ 'message' => 'Expires at cannot be a date in the past' })
+ expect(json_response).to eq({ 'message' => 'Expires at cannot be a date in the past' })
+ end
end
- end
- context 'when set to a date in the future' do
- let(:expires_at) { 5.days.from_now }
+ context 'when set to a date in the future' do
+ let(:expires_at) { 5.days.from_now }
- it 'updates the member' do
- subject
+ it 'updates the member' do
+ subject
- expect(requester.reload.expires_at).to eq(expires_at.to_date)
+ expect(requester.reload.expires_at).to eq(expires_at.to_date)
+ end
end
end
- end
- context 'expiration date' do
- let(:expiry_date) { 1.month.from_now.to_date }
+ context 'expiration date' do
+ let(:expiry_date) { 1.month.from_now.to_date }
- before do
- travel_to Time.now.utc.beginning_of_day
-
- put(
- :update,
- params: {
- project_member: { expires_at: expiry_date },
- namespace_id: project.namespace,
- project_id: project,
- id: requester
- },
- format: :json
- )
- end
+ before do
+ travel_to Time.now.utc.beginning_of_day
+
+ put(
+ :update,
+ params: {
+ project_member: { expires_at: expiry_date },
+ namespace_id: project.namespace,
+ project_id: project,
+ id: requester
+ },
+ format: :json
+ )
+ end
- context 'when `expires_at` is set' do
- it 'returns correct json response' do
- expect(json_response).to eq({
- "expires_soon" => false,
- "expires_at_formatted" => expiry_date.to_time.in_time_zone.to_s(:medium)
- })
+ context 'when `expires_at` is set' do
+ it 'returns correct json response' do
+ expect(json_response).to eq({
+ "expires_soon" => false,
+ "expires_at_formatted" => expiry_date.to_time.in_time_zone.to_s(:medium)
+ })
+ end
end
- end
- context 'when `expires_at` is not set' do
- let(:expiry_date) { nil }
+ context 'when `expires_at` is not set' do
+ let(:expiry_date) { nil }
- it 'returns empty json response' do
- expect(json_response).to be_empty
+ it 'returns empty json response' do
+ expect(json_response).to be_empty
+ end
end
end
end
- end
- describe 'DELETE destroy' do
- let_it_be(:member) { create(:project_member, :developer, project: project) }
+ describe 'DELETE destroy' do
+ let_it_be(:member) { create(:project_member, :developer, project: project) }
- before do
- sign_in(user)
- end
+ before do
+ sign_in(user)
+ end
- context 'when member is not found' do
- it 'returns 404' do
- delete :destroy, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: 42
- }
+ context 'when member is not found' do
+ it 'returns 404' do
+ delete :destroy, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: 42
+ }
- expect(response).to have_gitlab_http_status(:not_found)
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
end
- end
- context 'when member is found' do
- context 'when user does not have enough rights' do
- context 'when user does not have rights to manage other members' do
- before do
- project.add_developer(user)
+ context 'when member is found' do
+ context 'when user does not have enough rights' do
+ context 'when user does not have rights to manage other members' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'returns 404', :aggregate_failures do
+ delete :destroy, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: member
+ }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(project.members).to include member
+ end
end
- it 'returns 404', :aggregate_failures do
- delete :destroy, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: member
- }
+ context 'when user does not have rights to manage Owner members' do
+ let_it_be(:member) { create(:project_member, project: project, access_level: Gitlab::Access::OWNER) }
- expect(response).to have_gitlab_http_status(:not_found)
- expect(project.members).to include member
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'returns 403', :aggregate_failures do
+ delete :destroy, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: member
+ }
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(project.members).to include member
+ end
end
end
- context 'when user does not have rights to manage Owner members' do
- let_it_be(:member) { create(:project_member, project: project, access_level: Gitlab::Access::OWNER) }
-
+ context 'when user has enough rights' do
before do
project.add_maintainer(user)
end
- it 'returns 403', :aggregate_failures do
+ it '[HTML] removes user from members', :aggregate_failures do
+ delete :destroy, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: member
+ }
+
+ expect(response).to redirect_to(
+ project_project_members_path(project)
+ )
+ expect(project.members).not_to include member
+ end
+
+ it '[JS] removes user from members', :aggregate_failures do
delete :destroy, params: {
namespace_id: project.namespace,
project_id: project,
id: member
- }
+ }, xhr: true
- expect(response).to have_gitlab_http_status(:forbidden)
- expect(project.members).to include member
+ expect(response).to be_successful
+ expect(project.members).not_to include member
end
end
end
-
- context 'when user has enough rights' do
- before do
- project.add_maintainer(user)
- end
-
- it '[HTML] removes user from members', :aggregate_failures do
- delete :destroy, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: member
- }
-
- expect(response).to redirect_to(
- project_project_members_path(project)
- )
- expect(project.members).not_to include member
- end
-
- it '[JS] removes user from members', :aggregate_failures do
- delete :destroy, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: member
- }, xhr: true
-
- expect(response).to be_successful
- expect(project.members).not_to include member
- end
- end
- end
- end
-
- describe 'DELETE leave' do
- before do
- sign_in(user)
end
- context 'when member is not found' do
- it 'returns 404' do
- delete :leave, params: {
- namespace_id: project.namespace,
- project_id: project
- }
-
- expect(response).to have_gitlab_http_status(:not_found)
+ describe 'DELETE leave' do
+ before do
+ sign_in(user)
end
- end
-
- context 'when member is found' do
- context 'and is not an owner' do
- before do
- project.add_developer(user)
- end
- it 'removes user from members', :aggregate_failures do
+ context 'when member is not found' do
+ it 'returns 404' do
delete :leave, params: {
namespace_id: project.namespace,
project_id: project
}
- expect(controller).to set_flash.to "You left the \"#{project.human_name}\" project."
- expect(response).to redirect_to(dashboard_projects_path)
- expect(project.users).not_to include user
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
- context 'and is an owner' do
- let(:project) { create(:project, namespace: user.namespace) }
+ context 'when member is found' do
+ context 'and is not an owner' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'removes user from members', :aggregate_failures do
+ delete :leave, params: {
+ namespace_id: project.namespace,
+ project_id: project
+ }
- before do
- project.add_maintainer(user)
+ expect(controller).to set_flash.to "You left the \"#{project.human_name}\" project."
+ expect(response).to redirect_to(dashboard_projects_path)
+ expect(project.users).not_to include user
+ end
end
- it 'cannot remove themselves from the project' do
- delete :leave, params: {
- namespace_id: project.namespace,
- project_id: project
- }
+ context 'and is an owner' do
+ let(:project) { create(:project, namespace: user.namespace) }
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
+ before do
+ project.add_maintainer(user)
+ end
- context 'and is a requester' do
- before do
- project.request_access(user)
+ it 'cannot remove themselves from the project' do
+ delete :leave, params: {
+ namespace_id: project.namespace,
+ project_id: project
+ }
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
end
- it 'removes user from members', :aggregate_failures do
- delete :leave, params: {
- namespace_id: project.namespace,
- project_id: project
- }
+ context 'and is a requester' do
+ before do
+ project.request_access(user)
+ end
+
+ it 'removes user from members', :aggregate_failures do
+ delete :leave, params: {
+ namespace_id: project.namespace,
+ project_id: project
+ }
- expect(controller).to set_flash.to 'Your access request to the project has been withdrawn.'
- expect(response).to redirect_to(project_path(project))
- expect(project.requesters).to be_empty
- expect(project.users).not_to include user
+ expect(controller).to set_flash.to 'Your access request to the project has been withdrawn.'
+ expect(response).to redirect_to(project_path(project))
+ expect(project.requesters).to be_empty
+ expect(project.users).not_to include user
+ end
end
end
end
- end
-
- describe 'POST request_access' do
- before do
- sign_in(user)
- end
- it 'creates a new ProjectMember that is not a team member', :aggregate_failures do
- post :request_access, params: {
- namespace_id: project.namespace,
- project_id: project
- }
-
- expect(controller).to set_flash.to 'Your request for access has been queued for review.'
- expect(response).to redirect_to(
- project_path(project)
- )
- expect(project.requesters.exists?(user_id: user)).to be_truthy
- expect(project.users).not_to include user
- end
- end
+ describe 'POST request_access' do
+ before do
+ sign_in(user)
+ end
- describe 'POST approve' do
- let_it_be(:member) { create(:project_member, :access_request, project: project) }
+ it 'creates a new ProjectMember that is not a team member', :aggregate_failures do
+ post :request_access, params: {
+ namespace_id: project.namespace,
+ project_id: project
+ }
- before do
- sign_in(user)
+ expect(controller).to set_flash.to 'Your request for access has been queued for review.'
+ expect(response).to redirect_to(
+ project_path(project)
+ )
+ expect(project.requesters.exists?(user_id: user)).to be_truthy
+ expect(project.users).not_to include user
+ end
end
- context 'when member is not found' do
- it 'returns 404' do
- post :approve_access_request, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: 42
- }
+ describe 'POST approve' do
+ let_it_be(:member) { create(:project_member, :access_request, project: project) }
- expect(response).to have_gitlab_http_status(:not_found)
+ before do
+ sign_in(user)
end
- end
-
- context 'when member is found' do
- context 'when user does not have rights to manage other members' do
- before do
- project.add_developer(user)
- end
- it 'returns 404', :aggregate_failures do
+ context 'when member is not found' do
+ it 'returns 404' do
post :approve_access_request, params: {
namespace_id: project.namespace,
project_id: project,
- id: member
+ id: 42
}
expect(response).to have_gitlab_http_status(:not_found)
- expect(project.members).not_to include member
end
end
- context 'when user has enough rights' do
- before do
- project.add_maintainer(user)
+ context 'when member is found' do
+ context 'when user does not have rights to manage other members' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'returns 404', :aggregate_failures do
+ post :approve_access_request, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: member
+ }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(project.members).not_to include member
+ end
end
- it 'adds user to members', :aggregate_failures do
- post :approve_access_request, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: member
- }
+ context 'when user has enough rights' do
+ before do
+ project.add_maintainer(user)
+ end
- expect(response).to redirect_to(
- project_project_members_path(project)
- )
- expect(project.members).to include member
+ it 'adds user to members', :aggregate_failures do
+ post :approve_access_request, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: member
+ }
+
+ expect(response).to redirect_to(
+ project_project_members_path(project)
+ )
+ expect(project.members).to include member
+ end
end
end
end
- end
- describe 'POST resend_invite' do
- let_it_be(:member) { create(:project_member, project: project) }
+ describe 'POST resend_invite' do
+ let_it_be(:member) { create(:project_member, project: project) }
- before do
- project.add_maintainer(user)
- sign_in(user)
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ end
+
+ it 'is successful' do
+ post :resend_invite, params: { namespace_id: project.namespace, project_id: project, id: member }
+
+ expect(response).to have_gitlab_http_status(:found)
+ end
end
+ end
- it 'is successful' do
- post :resend_invite, params: { namespace_id: project.namespace, project_id: project, id: member }
+ it_behaves_like 'controller actions'
- expect(response).to have_gitlab_http_status(:found)
+ context 'when project_members_index_by_project_namespace feature flag is disabled' do
+ before do
+ stub_feature_flags(project_members_index_by_project_namespace: false)
end
+
+ it_behaves_like 'controller actions'
end
end
diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb
index 1c9aafacbd9..40252cf65cd 100644
--- a/spec/controllers/projects/raw_controller_spec.rb
+++ b/spec/controllers/projects/raw_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::RawController do
+RSpec.describe Projects::RawController, feature_category: :source_code_management do
include RepoHelpers
let_it_be(:project) { create(:project, :public, :repository) }
@@ -23,13 +23,13 @@ RSpec.describe Projects::RawController do
subject { get_show }
- shared_examples 'single Gitaly request' do
- it 'makes a single Gitaly request', :request_store, :clean_gitlab_redis_cache do
+ shared_examples 'limited number of Gitaly request' do
+ it 'makes a limited number of Gitaly request', :request_store, :clean_gitlab_redis_cache do
# Warm up to populate repository cache
get_show
RequestStore.clear!
- expect { get_show }.to change { Gitlab::GitalyClient.get_request_count }.by(1)
+ expect { get_show }.to change { Gitlab::GitalyClient.get_request_count }.by(2)
end
end
@@ -57,7 +57,7 @@ RSpec.describe Projects::RawController do
it_behaves_like 'project cache control headers'
it_behaves_like 'content disposition headers'
- include_examples 'single Gitaly request'
+ include_examples 'limited number of Gitaly request'
end
context 'image header' do
@@ -73,7 +73,7 @@ RSpec.describe Projects::RawController do
it_behaves_like 'project cache control headers'
it_behaves_like 'content disposition headers'
- include_examples 'single Gitaly request'
+ include_examples 'limited number of Gitaly request'
end
context 'with LFS files' do
@@ -82,7 +82,7 @@ RSpec.describe Projects::RawController do
it_behaves_like 'a controller that can serve LFS files'
it_behaves_like 'project cache control headers'
- include_examples 'single Gitaly request'
+ include_examples 'limited number of Gitaly request'
end
context 'when the endpoint receives requests above the limit' do
@@ -239,8 +239,10 @@ RSpec.describe Projects::RawController do
end
describe 'caching' do
+ let(:ref) { project.default_branch }
+
def request_file
- get(:show, params: { namespace_id: project.namespace, project_id: project, id: 'master/README.md' })
+ get(:show, params: { namespace_id: project.namespace, project_id: project, id: "#{ref}/README.md" })
end
it 'sets appropriate caching headers' do
@@ -254,6 +256,21 @@ RSpec.describe Projects::RawController do
)
end
+ context 'when a blob access by permalink' do
+ let(:ref) { project.commit.id }
+
+ it 'sets appropriate caching headers with longer max-age' do
+ sign_in create(:user)
+ request_file
+
+ expect(response.headers['ETag']).to eq("\"bdd5aa537c1e1f6d1b66de4bac8a6132\"")
+ expect(response.cache_control[:no_store]).to be_nil
+ expect(response.header['Cache-Control']).to eq(
+ 'max-age=3600, public, must-revalidate, stale-while-revalidate=60, stale-if-error=300, s-maxage=60'
+ )
+ end
+ end
+
context 'when a public project has private repo' do
let(:project) { create(:project, :public, :repository, :repository_private) }
let(:user) { create(:user, maintainer_projects: [project]) }
@@ -278,21 +295,6 @@ RSpec.describe Projects::RawController do
expect(response).to have_gitlab_http_status(:not_modified)
end
end
-
- context 'when improve_blobs_cache_headers disabled' do
- before do
- stub_feature_flags(improve_blobs_cache_headers: false)
- end
-
- it 'uses weak etags with a restricted set of headers' do
- sign_in create(:user)
- request_file
-
- expect(response.headers['ETag']).to eq("W/\"bdd5aa537c1e1f6d1b66de4bac8a6132\"")
- expect(response.cache_control[:no_store]).to be_nil
- expect(response.header['Cache-Control']).to eq('max-age=60, public')
- end
- end
end
end
end
diff --git a/spec/controllers/projects/refs_controller_spec.rb b/spec/controllers/projects/refs_controller_spec.rb
index a7a8361ae20..a0d119baf16 100644
--- a/spec/controllers/projects/refs_controller_spec.rb
+++ b/spec/controllers/projects/refs_controller_spec.rb
@@ -22,65 +22,30 @@ RSpec.describe Projects::RefsController, feature_category: :source_code_manageme
subject { get :switch, params: params }
- context 'when the use_ref_type_parameter feature flag is not enabled' do
- before do
- stub_feature_flags(use_ref_type_parameter: false)
- end
-
- where(:destination, :ref_type, :redirected_to) do
- 'tree' | nil | lazy { project_tree_path(project, id) }
- 'tree' | 'heads' | lazy { project_tree_path(project, id) }
- 'blob' | nil | lazy { project_blob_path(project, id) }
- 'blob' | 'heads' | lazy { project_blob_path(project, id) }
- 'graph' | nil | lazy { project_network_path(project, id) }
- 'graph' | 'heads' | lazy { project_network_path(project, id) }
- 'graphs' | nil | lazy { project_graph_path(project, id) }
- 'graphs' | 'heads' | lazy { project_graph_path(project, id) }
- 'find_file' | nil | lazy { project_find_file_path(project, id) }
- 'find_file' | 'heads' | lazy { project_find_file_path(project, id) }
- 'graphs_commits' | nil | lazy { commits_project_graph_path(project, id) }
- 'graphs_commits' | 'heads' | lazy { commits_project_graph_path(project, id) }
- 'badges' | nil | lazy { project_settings_ci_cd_path(project, ref: id) }
- 'badges' | 'heads' | lazy { project_settings_ci_cd_path(project, ref: id) }
- 'commits' | nil | lazy { project_commits_path(project, id) }
- 'commits' | 'heads' | lazy { project_commits_path(project, id) }
- 'somethingelse' | nil | lazy { project_commits_path(project, id) }
- 'somethingelse' | 'heads' | lazy { project_commits_path(project, id) }
- end
-
- with_them do
- it 'redirects to destination' do
- expect(subject).to redirect_to(redirected_to)
- end
- end
+ where(:destination, :ref_type, :redirected_to) do
+ 'tree' | nil | lazy { project_tree_path(project, id) }
+ 'tree' | 'heads' | lazy { project_tree_path(project, id) }
+ 'blob' | nil | lazy { project_blob_path(project, id) }
+ 'blob' | 'heads' | lazy { project_blob_path(project, id) }
+ 'graph' | nil | lazy { project_network_path(project, id) }
+ 'graph' | 'heads' | lazy { project_network_path(project, id, ref_type: 'heads') }
+ 'graphs' | nil | lazy { project_graph_path(project, id) }
+ 'graphs' | 'heads' | lazy { project_graph_path(project, id, ref_type: 'heads') }
+ 'find_file' | nil | lazy { project_find_file_path(project, id) }
+ 'find_file' | 'heads' | lazy { project_find_file_path(project, id) }
+ 'graphs_commits' | nil | lazy { commits_project_graph_path(project, id) }
+ 'graphs_commits' | 'heads' | lazy { commits_project_graph_path(project, id) }
+ 'badges' | nil | lazy { project_settings_ci_cd_path(project, ref: id) }
+ 'badges' | 'heads' | lazy { project_settings_ci_cd_path(project, ref: id) }
+ 'commits' | nil | lazy { project_commits_path(project, id) }
+ 'commits' | 'heads' | lazy { project_commits_path(project, id, ref_type: 'heads') }
+ nil | nil | lazy { project_commits_path(project, id) }
+ nil | 'heads' | lazy { project_commits_path(project, id, ref_type: 'heads') }
end
- context 'when the use_ref_type_parameter feature flag is enabled' do
- where(:destination, :ref_type, :redirected_to) do
- 'tree' | nil | lazy { project_tree_path(project, id) }
- 'tree' | 'heads' | lazy { project_tree_path(project, id) }
- 'blob' | nil | lazy { project_blob_path(project, id) }
- 'blob' | 'heads' | lazy { project_blob_path(project, id) }
- 'graph' | nil | lazy { project_network_path(project, id) }
- 'graph' | 'heads' | lazy { project_network_path(project, id, ref_type: 'heads') }
- 'graphs' | nil | lazy { project_graph_path(project, id) }
- 'graphs' | 'heads' | lazy { project_graph_path(project, id, ref_type: 'heads') }
- 'find_file' | nil | lazy { project_find_file_path(project, id) }
- 'find_file' | 'heads' | lazy { project_find_file_path(project, id) }
- 'graphs_commits' | nil | lazy { commits_project_graph_path(project, id) }
- 'graphs_commits' | 'heads' | lazy { commits_project_graph_path(project, id) }
- 'badges' | nil | lazy { project_settings_ci_cd_path(project, ref: id) }
- 'badges' | 'heads' | lazy { project_settings_ci_cd_path(project, ref: id) }
- 'commits' | nil | lazy { project_commits_path(project, id) }
- 'commits' | 'heads' | lazy { project_commits_path(project, id, ref_type: 'heads') }
- nil | nil | lazy { project_commits_path(project, id) }
- nil | 'heads' | lazy { project_commits_path(project, id, ref_type: 'heads') }
- end
-
- with_them do
- it 'redirects to destination' do
- expect(subject).to redirect_to(redirected_to)
- end
+ with_them do
+ it 'redirects to destination' do
+ expect(subject).to redirect_to(redirected_to)
end
end
end
diff --git a/spec/controllers/projects/repositories_controller_spec.rb b/spec/controllers/projects/repositories_controller_spec.rb
index 928428b5caf..8186176a46b 100644
--- a/spec/controllers/projects/repositories_controller_spec.rb
+++ b/spec/controllers/projects/repositories_controller_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Projects::RepositoriesController do
+RSpec.describe Projects::RepositoriesController, feature_category: :source_code_management do
let_it_be(:project) { create(:project, :repository) }
describe 'POST create' do
@@ -143,7 +143,9 @@ RSpec.describe Projects::RepositoriesController do
expect(response).to have_gitlab_http_status(:ok)
expect(response.header['ETag']).to be_present
- expect(response.header['Cache-Control']).to include('max-age=60, public')
+ expect(response.header['Cache-Control']).to eq(
+ 'max-age=60, public, must-revalidate, stale-while-revalidate=60, stale-if-error=300, s-maxage=60'
+ )
end
context 'and repo is private' do
@@ -154,7 +156,9 @@ RSpec.describe Projects::RepositoriesController do
expect(response).to have_gitlab_http_status(:ok)
expect(response.header['ETag']).to be_present
- expect(response.header['Cache-Control']).to include('max-age=60, private')
+ expect(response.header['Cache-Control']).to eq(
+ 'max-age=60, private, must-revalidate, stale-while-revalidate=60, stale-if-error=300, s-maxage=60'
+ )
end
end
end
@@ -164,7 +168,9 @@ RSpec.describe Projects::RepositoriesController do
get_archive('ddd0f15ae83993f5cb66a927a28673882e99100b')
expect(response).to have_gitlab_http_status(:ok)
- expect(response.header['Cache-Control']).to include('max-age=3600')
+ expect(response.header['Cache-Control']).to eq(
+ 'max-age=3600, private, must-revalidate, stale-while-revalidate=60, stale-if-error=300, s-maxage=60'
+ )
end
end
diff --git a/spec/controllers/projects/service_ping_controller_spec.rb b/spec/controllers/projects/service_ping_controller_spec.rb
index 10d4b897564..601dfd9b011 100644
--- a/spec/controllers/projects/service_ping_controller_spec.rb
+++ b/spec/controllers/projects/service_ping_controller_spec.rb
@@ -42,83 +42,6 @@ RSpec.describe Projects::ServicePingController do
end
end
- describe 'POST #web_ide_clientside_preview' do
- subject { post :web_ide_clientside_preview, params: { namespace_id: project.namespace, project_id: project } }
-
- context 'when web ide clientside preview is enabled' do
- before do
- stub_application_setting(web_ide_clientside_preview_enabled: true)
- end
-
- it_behaves_like 'counter is not increased'
- it_behaves_like 'counter is increased', 'WEB_IDE_PREVIEWS_COUNT'
- end
-
- context 'when web ide clientside preview is not enabled' do
- let(:user) { project.first_owner }
-
- before do
- stub_application_setting(web_ide_clientside_preview_enabled: false)
- end
-
- it 'returns 404' do
- subject
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-
- describe 'POST #web_ide_clientside_preview_success' do
- subject { post :web_ide_clientside_preview_success, params: { namespace_id: project.namespace, project_id: project } }
-
- context 'when web ide clientside preview is enabled' do
- before do
- stub_application_setting(web_ide_clientside_preview_enabled: true)
- end
-
- it_behaves_like 'counter is not increased'
- it_behaves_like 'counter is increased', 'WEB_IDE_PREVIEWS_SUCCESS_COUNT'
-
- context 'when the user has access to the project', :snowplow do
- let(:user) { project.owner }
-
- it 'increases the live preview view counter' do
- expect(Gitlab::UsageDataCounters::EditorUniqueCounter).to receive(:track_live_preview_edit_action).with(author: user, project: project)
-
- subject
-
- expect(response).to have_gitlab_http_status(:ok)
- end
-
- it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:project) { create(:project) }
- let(:namespace) { project.namespace }
- let(:category) { 'Gitlab::UsageDataCounters::EditorUniqueCounter' }
- let(:action) { 'ide_edit' }
- let(:property) { 'g_edit_by_live_preview' }
- let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_ide_edit' }
- let(:context) { [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context] }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
- end
- end
- end
-
- context 'when web ide clientside preview is not enabled' do
- let(:user) { project.owner }
-
- before do
- stub_application_setting(web_ide_clientside_preview_enabled: false)
- end
-
- it 'returns 404' do
- subject
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-
describe 'POST #web_ide_pipelines_count' do
subject { post :web_ide_pipelines_count, params: { namespace_id: project.namespace, project_id: project } }
diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
index dcd1072612a..ba917fa3a31 100644
--- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb
+++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
@@ -2,7 +2,7 @@
require('spec_helper')
-RSpec.describe Projects::Settings::CiCdController do
+RSpec.describe Projects::Settings::CiCdController, feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let_it_be(:project_auto_devops) { create(:project_auto_devops) }
diff --git a/spec/controllers/projects/settings/repository_controller_spec.rb b/spec/controllers/projects/settings/repository_controller_spec.rb
index 51ea2e5d7c6..781e4ff7b00 100644
--- a/spec/controllers/projects/settings/repository_controller_spec.rb
+++ b/spec/controllers/projects/settings/repository_controller_spec.rb
@@ -19,40 +19,6 @@ RSpec.describe Projects::Settings::RepositoryController, feature_category: :sour
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:show)
end
-
- context 'when feature flag `group_protected_branches` disabled' do
- before do
- stub_feature_flags(group_protected_branches: false)
- end
-
- it 'does not assign instance variable `protected_group_branches`' do
- get :show, params: base_params
-
- expect(assigns).not_to include(:protected_group_branches)
- end
- end
-
- context 'when feature flag `group_protected_branches` enabled' do
- context 'when the root namespace is a user' do
- it 'assigns empty instance variable `protected_group_branches`' do
- get :show, params: base_params
-
- expect(assigns[:protected_group_branches]).to eq([])
- end
- end
-
- context 'when the root namespace is a group' do
- let_it_be(:project) { create(:project_empty_repo, :public, :in_group) }
-
- let(:protected_group_branch) { create(:protected_branch, group: project.root_namespace, project: nil) }
-
- it 'assigns instance variable `protected_group_branches`' do
- get :show, params: base_params
-
- expect(assigns[:protected_group_branches]).to include(protected_group_branch)
- end
- end
- end
end
describe 'PUT cleanup' do
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index bc58eaa1d6f..51f8a3b1197 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -2,7 +2,7 @@
require('spec_helper')
-RSpec.describe ProjectsController do
+RSpec.describe ProjectsController, feature_category: :projects do
include ExternalAuthorizationServiceHelpers
include ProjectForksHelper
using RSpec::Parameterized::TableSyntax
@@ -629,29 +629,66 @@ RSpec.describe ProjectsController do
describe '#housekeeping' do
let_it_be(:group) { create(:group) }
- let_it_be(:project) { create(:project, group: group) }
+ let(:housekeeping_service_dbl) { instance_double(Repositories::HousekeepingService) }
+ let(:params) do
+ {
+ namespace_id: project.namespace.path,
+ id: project.path,
+ prune: prune
+ }
+ end
+ let(:prune) { nil }
+ let_it_be(:project) { create(:project, group: group) }
let(:housekeeping) { Repositories::HousekeepingService.new(project) }
+ subject { post :housekeeping, params: params }
+
context 'when authenticated as owner' do
before do
group.add_owner(user)
sign_in(user)
- allow(Repositories::HousekeepingService).to receive(:new).with(project, :gc).and_return(housekeeping)
+ allow(Repositories::HousekeepingService).to receive(:new).with(project, :eager).and_return(housekeeping)
end
it 'forces a full garbage collection' do
expect(housekeeping).to receive(:execute).once
post :housekeeping,
- params: {
- namespace_id: project.namespace.path,
- id: project.path
- }
+ params: {
+ namespace_id: project.namespace.path,
+ id: project.path
+ }
expect(response).to have_gitlab_http_status(:found)
end
+
+ it 'logs an audit event' do
+ expect(housekeeping).to receive(:execute).once.and_yield
+
+ expect(::Gitlab::Audit::Auditor).to receive(:audit).with(a_hash_including(
+ name: 'manually_trigger_housekeeping',
+ author: user,
+ scope: project,
+ target: project,
+ message: "Housekeeping task: eager"
+ ))
+
+ subject
+ end
+
+ context 'and requesting prune' do
+ let(:prune) { true }
+
+ it 'enqueues pruning' do
+ allow(Repositories::HousekeepingService).to receive(:new).with(project, :prune).and_return(housekeeping_service_dbl)
+ expect(housekeeping_service_dbl).to receive(:execute)
+
+ subject
+ expect(response).to have_gitlab_http_status(:found)
+ end
+ end
end
context 'when authenticated as developer' do
@@ -665,10 +702,10 @@ RSpec.describe ProjectsController do
expect(housekeeping).not_to receive(:execute)
post :housekeeping,
- params: {
- namespace_id: project.namespace.path,
- id: project.path
- }
+ params: {
+ namespace_id: project.namespace.path,
+ id: project.path
+ }
expect(response).to have_gitlab_http_status(:found)
end
diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb
index d0439a18158..b217b100349 100644
--- a/spec/controllers/registrations_controller_spec.rb
+++ b/spec/controllers/registrations_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RegistrationsController do
+RSpec.describe RegistrationsController, feature_category: :user_profile do
include TermsHelper
include FullNameHelper
@@ -215,11 +215,18 @@ RSpec.describe RegistrationsController do
property: member.id.to_s,
user: member.reload.user
)
+
+ expect_snowplow_event(
+ category: 'RegistrationsController',
+ action: 'create_user',
+ label: 'invited',
+ user: member.reload.user
+ )
end
end
context 'when member does not exist from the session key value' do
- let(:originating_member_id) { -1 }
+ let(:originating_member_id) { nil }
it 'does not track invite acceptance' do
subject
@@ -229,6 +236,13 @@ RSpec.describe RegistrationsController do
action: 'accepted',
label: 'invite_email'
)
+
+ expect_snowplow_event(
+ category: 'RegistrationsController',
+ action: 'create_user',
+ label: 'signup',
+ user: member.reload.user
+ )
end
end
end
diff --git a/spec/controllers/root_controller_spec.rb b/spec/controllers/root_controller_spec.rb
index c6a8cee2f70..6fa1d93265d 100644
--- a/spec/controllers/root_controller_spec.rb
+++ b/spec/controllers/root_controller_spec.rb
@@ -37,16 +37,16 @@ RSpec.describe RootController do
user.dashboard = 'stars'
end
- it 'redirects to their specified dashboard' do
+ it 'redirects to their starred projects list' do
get :index
expect(response).to redirect_to starred_dashboard_projects_path
end
end
- context 'who has customized their dashboard setting for project activities' do
+ context 'who has customized their dashboard setting for their own activities' do
before do
- user.dashboard = 'project_activity'
+ user.dashboard = 'your_activity'
end
it 'redirects to the activity list' do
@@ -56,12 +56,24 @@ RSpec.describe RootController do
end
end
+ context 'who has customized their dashboard setting for project activities' do
+ before do
+ user.dashboard = 'project_activity'
+ end
+
+ it 'redirects to the projects activity list' do
+ get :index
+
+ expect(response).to redirect_to activity_dashboard_path(filter: 'projects')
+ end
+ end
+
context 'who has customized their dashboard setting for starred project activities' do
before do
user.dashboard = 'starred_project_activity'
end
- it 'redirects to the activity list' do
+ it 'redirects to their starred projects activity list' do
get :index
expect(response).to redirect_to activity_dashboard_path(filter: 'starred')
@@ -73,7 +85,7 @@ RSpec.describe RootController do
user.dashboard = 'followed_user_activity'
end
- it 'redirects to the activity list' do
+ it 'redirects to the followed users activity list' do
get :index
expect(response).to redirect_to activity_dashboard_path(filter: 'followed')
diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb
index 37fc5a033ba..0f7f4a1910b 100644
--- a/spec/controllers/search_controller_spec.rb
+++ b/spec/controllers/search_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SearchController do
+RSpec.describe SearchController, feature_category: :global_search do
include ExternalAuthorizationServiceHelpers
context 'authorized user' do
@@ -359,12 +359,13 @@ RSpec.describe SearchController do
end.to raise_error(ActionController::ParameterMissing)
end
- it 'sets private cache control headers' do
+ it 'sets correct cache control headers' do
get :count, params: { search: 'hello', scope: 'projects' }
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Cache-Control']).to eq('max-age=60, private')
+ expect(response.headers['Pragma']).to be_nil
end
it 'does NOT blow up if search param is NOT a string' do
diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb
index 78b3cc63b08..1f7d169bae5 100644
--- a/spec/controllers/sessions_controller_spec.rb
+++ b/spec/controllers/sessions_controller_spec.rb
@@ -221,7 +221,7 @@ RSpec.describe SessionsController do
expect(Gitlab::Metrics).to receive(:counter)
.with(:successful_login_captcha_total, anything)
.and_return(counter)
- expect(Gitlab::Metrics).to receive(:counter).and_call_original
+ expect(Gitlab::Metrics).to receive(:counter).at_least(1).time.and_call_original
post(:create, params: { user: user_params }, session: sesion_params)
end