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>2021-10-20 11:43:02 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-10-20 11:43:02 +0300
commitd9ab72d6080f594d0b3cae15f14b3ef2c6c638cb (patch)
tree2341ef426af70ad1e289c38036737e04b0aa5007 /spec/controllers
parentd6e514dd13db8947884cd58fe2a9c2a063400a9b (diff)
Add latest changes from gitlab-org/gitlab@14-4-stable-eev14.4.0-rc42
Diffstat (limited to 'spec/controllers')
-rw-r--r--spec/controllers/admin/instance_review_controller_spec.rb6
-rw-r--r--spec/controllers/admin/serverless/domains_controller_spec.rb370
-rw-r--r--spec/controllers/admin/topics/avatars_controller_spec.rb20
-rw-r--r--spec/controllers/admin/topics_controller_spec.rb131
-rw-r--r--spec/controllers/application_controller_spec.rb12
-rw-r--r--spec/controllers/boards/issues_controller_spec.rb2
-rw-r--r--spec/controllers/concerns/group_tree_spec.rb112
-rw-r--r--spec/controllers/dashboard/milestones_controller_spec.rb7
-rw-r--r--spec/controllers/every_controller_spec.rb19
-rw-r--r--spec/controllers/graphql_controller_spec.rb8
-rw-r--r--spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb176
-rw-r--r--spec/controllers/groups/registry/repositories_controller_spec.rb25
-rw-r--r--spec/controllers/help_controller_spec.rb8
-rw-r--r--spec/controllers/import/bulk_imports_controller_spec.rb102
-rw-r--r--spec/controllers/jira_connect/app_descriptor_controller_spec.rb15
-rw-r--r--spec/controllers/jira_connect/events_controller_spec.rb165
-rw-r--r--spec/controllers/metrics_controller_spec.rb6
-rw-r--r--spec/controllers/profiles/two_factor_auths_controller_spec.rb6
-rw-r--r--spec/controllers/profiles_controller_spec.rb5
-rw-r--r--spec/controllers/projects/alerting/notifications_controller_spec.rb112
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb22
-rw-r--r--spec/controllers/projects/compare_controller_spec.rb2
-rw-r--r--spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb2
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb61
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb13
-rw-r--r--spec/controllers/projects/pipeline_schedules_controller_spec.rb2
-rw-r--r--spec/controllers/projects/raw_controller_spec.rb2
-rw-r--r--spec/controllers/projects/registry/repositories_controller_spec.rb13
-rw-r--r--spec/controllers/projects/tags_controller_spec.rb19
-rw-r--r--spec/controllers/projects/usage_quotas_controller_spec.rb20
-rw-r--r--spec/controllers/projects_controller_spec.rb85
-rw-r--r--spec/controllers/registrations_controller_spec.rb16
-rw-r--r--spec/controllers/repositories/git_http_controller_spec.rb25
-rw-r--r--spec/controllers/search_controller_spec.rb12
-rw-r--r--spec/controllers/uploads_controller_spec.rb40
35 files changed, 964 insertions, 677 deletions
diff --git a/spec/controllers/admin/instance_review_controller_spec.rb b/spec/controllers/admin/instance_review_controller_spec.rb
index d15894eeb5d..898cd30cdca 100644
--- a/spec/controllers/admin/instance_review_controller_spec.rb
+++ b/spec/controllers/admin/instance_review_controller_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Admin::InstanceReviewController do
include UsageDataHelpers
let(:admin) { create(:admin) }
- let(:subscriptions_url) { ::Gitlab::SubscriptionPortal::SUBSCRIPTIONS_URL }
+ let(:subscriptions_instance_review_url) { Gitlab::SubscriptionPortal.subscriptions_instance_review_url }
before do
sign_in(admin)
@@ -44,7 +44,7 @@ RSpec.describe Admin::InstanceReviewController do
notes_count: 0
} }.to_query
- expect(response).to redirect_to("#{subscriptions_url}/instance_review?#{params}")
+ expect(response).to redirect_to("#{subscriptions_instance_review_url}?#{params}")
end
end
@@ -61,7 +61,7 @@ RSpec.describe Admin::InstanceReviewController do
version: ::Gitlab::VERSION
} }.to_query
- expect(response).to redirect_to("#{subscriptions_url}/instance_review?#{params}")
+ expect(response).to redirect_to("#{subscriptions_instance_review_url}?#{params}")
end
end
end
diff --git a/spec/controllers/admin/serverless/domains_controller_spec.rb b/spec/controllers/admin/serverless/domains_controller_spec.rb
deleted file mode 100644
index e7503fb37fa..00000000000
--- a/spec/controllers/admin/serverless/domains_controller_spec.rb
+++ /dev/null
@@ -1,370 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Admin::Serverless::DomainsController do
- let(:admin) { create(:admin) }
- let(:user) { create(:user) }
-
- describe '#index' do
- context 'non-admin user' do
- before do
- sign_in(user)
- end
-
- it 'responds with 404' do
- get :index
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'admin user' do
- before do
- create(:pages_domain)
- sign_in(admin)
- end
-
- context 'with serverless_domain feature disabled' do
- before do
- stub_feature_flags(serverless_domain: false)
- end
-
- it 'responds with 404' do
- get :index
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'when instance-level serverless domain exists' do
- let!(:serverless_domain) { create(:pages_domain, :instance_serverless) }
-
- it 'loads the instance serverless domain' do
- get :index
-
- expect(assigns(:domain).id).to eq(serverless_domain.id)
- end
- end
-
- context 'when domain does not exist' do
- it 'initializes an instance serverless domain' do
- get :index
-
- domain = assigns(:domain)
-
- expect(domain.persisted?).to eq(false)
- expect(domain.wildcard).to eq(true)
- expect(domain.scope).to eq('instance')
- expect(domain.usage).to eq('serverless')
- end
- end
- end
- end
-
- describe '#create' do
- let(:create_params) do
- sample_domain = build(:pages_domain)
-
- {
- domain: 'serverless.gitlab.io',
- user_provided_certificate: sample_domain.certificate,
- user_provided_key: sample_domain.key
- }
- end
-
- context 'non-admin user' do
- before do
- sign_in(user)
- end
-
- it 'responds with 404' do
- post :create, params: { pages_domain: create_params }
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'admin user' do
- before do
- sign_in(admin)
- end
-
- context 'with serverless_domain feature disabled' do
- before do
- stub_feature_flags(serverless_domain: false)
- end
-
- it 'responds with 404' do
- post :create, params: { pages_domain: create_params }
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'when an instance-level serverless domain exists' do
- let!(:serverless_domain) { create(:pages_domain, :instance_serverless) }
-
- it 'does not create a new domain' do
- expect { post :create, params: { pages_domain: create_params } }.not_to change { PagesDomain.instance_serverless.count }
- end
-
- it 'redirects to index' do
- post :create, params: { pages_domain: create_params }
-
- expect(response).to redirect_to admin_serverless_domains_path
- expect(flash[:notice]).to include('An instance-level serverless domain already exists.')
- end
- end
-
- context 'when an instance-level serverless domain does not exist' do
- it 'creates an instance serverless domain with the provided attributes' do
- expect { post :create, params: { pages_domain: create_params } }.to change { PagesDomain.instance_serverless.count }.by(1)
-
- domain = PagesDomain.instance_serverless.first
- expect(domain.domain).to eq(create_params[:domain])
- expect(domain.certificate).to eq(create_params[:user_provided_certificate])
- expect(domain.key).to eq(create_params[:user_provided_key])
- expect(domain.wildcard).to eq(true)
- expect(domain.scope).to eq('instance')
- expect(domain.usage).to eq('serverless')
- end
-
- it 'redirects to index' do
- post :create, params: { pages_domain: create_params }
-
- expect(response).to redirect_to admin_serverless_domains_path
- expect(flash[:notice]).to include('Domain was successfully created.')
- end
- end
-
- context 'when there are errors' do
- it 'renders index view' do
- post :create, params: { pages_domain: { foo: 'bar' } }
-
- expect(assigns(:domain).errors.size).to be > 0
- expect(response).to render_template('index')
- end
- end
- end
- end
-
- describe '#update' do
- let(:domain) { create(:pages_domain, :instance_serverless) }
-
- let(:update_params) do
- sample_domain = build(:pages_domain)
-
- {
- user_provided_certificate: sample_domain.certificate,
- user_provided_key: sample_domain.key
- }
- end
-
- context 'non-admin user' do
- before do
- sign_in(user)
- end
-
- it 'responds with 404' do
- put :update, params: { id: domain.id, pages_domain: update_params }
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'admin user' do
- before do
- sign_in(admin)
- end
-
- context 'with serverless_domain feature disabled' do
- before do
- stub_feature_flags(serverless_domain: false)
- end
-
- it 'responds with 404' do
- put :update, params: { id: domain.id, pages_domain: update_params }
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'when domain exists' do
- it 'updates the domain with the provided attributes' do
- new_certificate = build(:pages_domain, :ecdsa).certificate
- new_key = build(:pages_domain, :ecdsa).key
-
- put :update, params: { id: domain.id, pages_domain: { user_provided_certificate: new_certificate, user_provided_key: new_key } }
-
- domain.reload
-
- expect(domain.certificate).to eq(new_certificate)
- expect(domain.key).to eq(new_key)
- end
-
- it 'does not update the domain name' do
- put :update, params: { id: domain.id, pages_domain: { domain: 'new.com' } }
-
- expect(domain.reload.domain).not_to eq('new.com')
- end
-
- it 'redirects to index' do
- put :update, params: { id: domain.id, pages_domain: update_params }
-
- expect(response).to redirect_to admin_serverless_domains_path
- expect(flash[:notice]).to include('Domain was successfully updated.')
- end
- end
-
- context 'when domain does not exist' do
- it 'returns 404' do
- put :update, params: { id: 0, pages_domain: update_params }
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'when there are errors' do
- it 'renders index view' do
- put :update, params: { id: domain.id, pages_domain: { user_provided_certificate: 'bad certificate' } }
-
- expect(assigns(:domain).errors.size).to be > 0
- expect(response).to render_template('index')
- end
- end
- end
- end
-
- describe '#verify' do
- let(:domain) { create(:pages_domain, :instance_serverless) }
-
- context 'non-admin user' do
- before do
- sign_in(user)
- end
-
- it 'responds with 404' do
- post :verify, params: { id: domain.id }
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'admin user' do
- before do
- sign_in(admin)
- end
-
- def stub_service
- service = double(:service)
-
- expect(VerifyPagesDomainService).to receive(:new).with(domain).and_return(service)
-
- service
- end
-
- context 'with serverless_domain feature disabled' do
- before do
- stub_feature_flags(serverless_domain: false)
- end
-
- it 'responds with 404' do
- post :verify, params: { id: domain.id }
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- it 'handles verification success' do
- expect(stub_service).to receive(:execute).and_return(status: :success)
-
- post :verify, params: { id: domain.id }
-
- expect(response).to redirect_to admin_serverless_domains_path
- expect(flash[:notice]).to eq('Successfully verified domain ownership')
- end
-
- it 'handles verification failure' do
- expect(stub_service).to receive(:execute).and_return(status: :failed)
-
- post :verify, params: { id: domain.id }
-
- expect(response).to redirect_to admin_serverless_domains_path
- expect(flash[:alert]).to eq('Failed to verify domain ownership')
- end
- end
- end
-
- describe '#destroy' do
- let!(:domain) { create(:pages_domain, :instance_serverless) }
-
- context 'non-admin user' do
- before do
- sign_in(user)
- end
-
- it 'responds with 404' do
- delete :destroy, params: { id: domain.id }
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'admin user' do
- before do
- sign_in(admin)
- end
-
- context 'with serverless_domain feature disabled' do
- before do
- stub_feature_flags(serverless_domain: false)
- end
-
- it 'responds with 404' do
- delete :destroy, params: { id: domain.id }
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'when domain exists' do
- context 'and is not associated to any clusters' do
- it 'deletes the domain' do
- expect { delete :destroy, params: { id: domain.id } }
- .to change { PagesDomain.count }.from(1).to(0)
-
- expect(response).to have_gitlab_http_status(:found)
- expect(flash[:notice]).to include('Domain was successfully deleted.')
- end
- end
-
- context 'and is associated to any clusters' do
- before do
- create(:serverless_domain_cluster, pages_domain: domain)
- end
-
- it 'does not delete the domain' do
- expect { delete :destroy, params: { id: domain.id } }
- .not_to change { PagesDomain.count }
-
- expect(response).to have_gitlab_http_status(:conflict)
- expect(flash[:notice]).to include('Domain cannot be deleted while associated to one or more clusters.')
- end
- end
- end
-
- context 'when domain does not exist' do
- before do
- domain.destroy!
- end
-
- it 'responds with 404' do
- delete :destroy, params: { id: domain.id }
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
- end
-end
diff --git a/spec/controllers/admin/topics/avatars_controller_spec.rb b/spec/controllers/admin/topics/avatars_controller_spec.rb
new file mode 100644
index 00000000000..7edc0e0c497
--- /dev/null
+++ b/spec/controllers/admin/topics/avatars_controller_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Admin::Topics::AvatarsController do
+ let(:user) { create(:admin) }
+ let(:topic) { create(:topic, avatar: fixture_file_upload("spec/fixtures/dk.png")) }
+
+ before do
+ sign_in(user)
+ controller.instance_variable_set(:@topic, topic)
+ end
+
+ it 'removes avatar from DB by calling destroy' do
+ delete :destroy, params: { topic_id: topic.id }
+ @topic = assigns(:topic)
+ expect(@topic.avatar.present?).to be_falsey
+ expect(@topic).to be_valid
+ end
+end
diff --git a/spec/controllers/admin/topics_controller_spec.rb b/spec/controllers/admin/topics_controller_spec.rb
new file mode 100644
index 00000000000..6d66cb43338
--- /dev/null
+++ b/spec/controllers/admin/topics_controller_spec.rb
@@ -0,0 +1,131 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Admin::TopicsController do
+ let_it_be(:topic) { create(:topic, name: 'topic') }
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:user) { create(:user) }
+
+ before do
+ sign_in(admin)
+ end
+
+ describe 'GET #index' do
+ it 'renders the template' do
+ get :index
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('index')
+ end
+
+ context 'as a normal user' do
+ before do
+ sign_in(user)
+ end
+
+ it 'renders a 404 error' do
+ get :index
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ describe 'GET #new' do
+ it 'renders the template' do
+ get :new
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('new')
+ end
+
+ context 'as a normal user' do
+ before do
+ sign_in(user)
+ end
+
+ it 'renders a 404 error' do
+ get :new
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ describe 'GET #edit' do
+ it 'renders the template' do
+ get :edit, params: { id: topic.id }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('edit')
+ end
+
+ context 'as a normal user' do
+ before do
+ sign_in(user)
+ end
+
+ it 'renders a 404 error' do
+ get :edit, params: { id: topic.id }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ describe 'POST #create' do
+ it 'creates topic' do
+ expect do
+ post :create, params: { projects_topic: { name: 'test' } }
+ end.to change { Projects::Topic.count }.by(1)
+ end
+
+ it 'shows error message for invalid topic' do
+ post :create, params: { projects_topic: { name: nil } }
+
+ errors = assigns[:topic].errors
+ expect(errors).to contain_exactly(errors.full_message(:name, I18n.t('errors.messages.blank')))
+ end
+
+ context 'as a normal user' do
+ before do
+ sign_in(user)
+ end
+
+ it 'renders a 404 error' do
+ post :create, params: { projects_topic: { name: 'test' } }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ describe 'PUT #update' do
+ it 'updates topic' do
+ put :update, params: { id: topic.id, projects_topic: { name: 'test' } }
+
+ expect(response).to redirect_to(edit_admin_topic_path(topic))
+ expect(topic.reload.name).to eq('test')
+ end
+
+ it 'shows error message for invalid topic' do
+ put :update, params: { id: topic.id, projects_topic: { name: nil } }
+
+ errors = assigns[:topic].errors
+ expect(errors).to contain_exactly(errors.full_message(:name, I18n.t('errors.messages.blank')))
+ end
+
+ context 'as a normal user' do
+ before do
+ sign_in(user)
+ end
+
+ it 'renders a 404 error' do
+ put :update, params: { id: topic.id, projects_topic: { name: 'test' } }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 218aa04dd3f..e9a49319f21 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -704,7 +704,7 @@ RSpec.describe ApplicationController do
get :index
- expect(response.headers['Cache-Control']).to eq 'no-store'
+ expect(response.headers['Cache-Control']).to eq 'private, no-store'
expect(response.headers['Pragma']).to eq 'no-cache'
end
@@ -740,7 +740,7 @@ RSpec.describe ApplicationController do
it 'sets no-cache headers', :aggregate_failures do
subject
- expect(response.headers['Cache-Control']).to eq 'no-store'
+ expect(response.headers['Cache-Control']).to eq 'private, no-store'
expect(response.headers['Pragma']).to eq 'no-cache'
expect(response.headers['Expires']).to eq 'Fri, 01 Jan 1990 00:00:00 GMT'
end
@@ -967,6 +967,14 @@ RSpec.describe ApplicationController do
end
end
+ describe '.endpoint_id_for_action' do
+ controller(described_class) { }
+
+ it 'returns an expected endpoint id' do
+ expect(controller.class.endpoint_id_for_action('hello')).to eq('AnonymousController#hello')
+ end
+ end
+
describe '#current_user' do
controller(described_class) do
def index; end
diff --git a/spec/controllers/boards/issues_controller_spec.rb b/spec/controllers/boards/issues_controller_spec.rb
index cc60ab16d2e..b2200050e41 100644
--- a/spec/controllers/boards/issues_controller_spec.rb
+++ b/spec/controllers/boards/issues_controller_spec.rb
@@ -116,7 +116,7 @@ RSpec.describe Boards::IssuesController do
it 'does not query issues table more than once' do
recorder = ActiveRecord::QueryRecorder.new { list_issues(user: user, board: board, list: list1) }
- query_count = recorder.occurrences.select { |query,| query.start_with?('SELECT issues.*') }.each_value.first
+ query_count = recorder.occurrences.select { |query,| query.match?(/FROM "?issues"?/) }.each_value.first
expect(query_count).to eq(1)
end
diff --git a/spec/controllers/concerns/group_tree_spec.rb b/spec/controllers/concerns/group_tree_spec.rb
index a0707688e54..e808f1caa6e 100644
--- a/spec/controllers/concerns/group_tree_spec.rb
+++ b/spec/controllers/concerns/group_tree_spec.rb
@@ -21,82 +21,94 @@ RSpec.describe GroupTree do
end
describe 'GET #index' do
- it 'filters groups' do
- other_group = create(:group, name: 'filter')
- other_group.add_owner(user)
+ shared_examples 'returns filtered groups' do
+ it 'filters groups' do
+ other_group = create(:group, name: 'filter')
+ other_group.add_owner(user)
- get :index, params: { filter: 'filt' }, format: :json
+ get :index, params: { filter: 'filt' }, format: :json
- expect(assigns(:groups)).to contain_exactly(other_group)
- end
+ expect(assigns(:groups)).to contain_exactly(other_group)
+ end
- context 'for subgroups' do
- it 'only renders root groups when no parent was given' do
- create(:group, :public, parent: group)
+ context 'for subgroups' do
+ it 'only renders root groups when no parent was given' do
+ create(:group, :public, parent: group)
- get :index, format: :json
+ get :index, format: :json
- expect(assigns(:groups)).to contain_exactly(group)
- end
+ expect(assigns(:groups)).to contain_exactly(group)
+ end
- it 'contains only the subgroup when a parent was given' do
- subgroup = create(:group, :public, parent: group)
+ it 'contains only the subgroup when a parent was given' do
+ subgroup = create(:group, :public, parent: group)
- get :index, params: { parent_id: group.id }, format: :json
+ get :index, params: { parent_id: group.id }, format: :json
- expect(assigns(:groups)).to contain_exactly(subgroup)
- end
+ expect(assigns(:groups)).to contain_exactly(subgroup)
+ end
- it 'allows filtering for subgroups and includes the parents for rendering' do
- subgroup = create(:group, :public, parent: group, name: 'filter')
+ it 'allows filtering for subgroups and includes the parents for rendering' do
+ subgroup = create(:group, :public, parent: group, name: 'filter')
- get :index, params: { filter: 'filt' }, format: :json
+ get :index, params: { filter: 'filt' }, format: :json
- expect(assigns(:groups)).to contain_exactly(group, subgroup)
- end
+ expect(assigns(:groups)).to contain_exactly(group, subgroup)
+ end
- it 'does not include groups the user does not have access to' do
- parent = create(:group, :private)
- subgroup = create(:group, :private, parent: parent, name: 'filter')
- subgroup.add_developer(user)
- _other_subgroup = create(:group, :private, parent: parent, name: 'filte')
+ it 'does not include groups the user does not have access to' do
+ parent = create(:group, :private)
+ subgroup = create(:group, :private, parent: parent, name: 'filter')
+ subgroup.add_developer(user)
+ _other_subgroup = create(:group, :private, parent: parent, name: 'filte')
- get :index, params: { filter: 'filt' }, format: :json
+ get :index, params: { filter: 'filt' }, format: :json
- expect(assigns(:groups)).to contain_exactly(parent, subgroup)
- end
+ expect(assigns(:groups)).to contain_exactly(parent, subgroup)
+ end
- it 'preloads parents regardless of pagination' do
- allow(Kaminari.config).to receive(:default_per_page).and_return(1)
- group = create(:group, :public)
- subgroup = create(:group, :public, parent: group)
- search_result = create(:group, :public, name: 'result', parent: subgroup)
+ it 'preloads parents regardless of pagination' do
+ allow(Kaminari.config).to receive(:default_per_page).and_return(1)
+ group = create(:group, :public)
+ subgroup = create(:group, :public, parent: group)
+ search_result = create(:group, :public, name: 'result', parent: subgroup)
- get :index, params: { filter: 'resu' }, format: :json
+ get :index, params: { filter: 'resu' }, format: :json
- expect(assigns(:groups)).to contain_exactly(group, subgroup, search_result)
+ expect(assigns(:groups)).to contain_exactly(group, subgroup, search_result)
+ end
end
- end
- context 'json content' do
- it 'shows groups as json' do
- get :index, format: :json
+ context 'json content' do
+ it 'shows groups as json' do
+ get :index, format: :json
- expect(json_response.first['id']).to eq(group.id)
- end
+ expect(json_response.first['id']).to eq(group.id)
+ end
- context 'nested groups' do
- it 'expands the tree when filtering' do
- subgroup = create(:group, :public, parent: group, name: 'filter')
+ context 'nested groups' do
+ it 'expands the tree when filtering' do
+ subgroup = create(:group, :public, parent: group, name: 'filter')
- get :index, params: { filter: 'filt' }, format: :json
+ get :index, params: { filter: 'filt' }, format: :json
- children_response = json_response.first['children']
+ children_response = json_response.first['children']
- expect(json_response.first['id']).to eq(group.id)
- expect(children_response.first['id']).to eq(subgroup.id)
+ expect(json_response.first['id']).to eq(group.id)
+ expect(children_response.first['id']).to eq(subgroup.id)
+ end
end
end
end
+
+ it_behaves_like 'returns filtered groups'
+
+ context 'when feature flag :linear_group_tree_ancestor_scopes is disabled' do
+ before do
+ stub_feature_flags(linear_group_tree_ancestor_scopes: false)
+ end
+
+ it_behaves_like 'returns filtered groups'
+ end
end
end
diff --git a/spec/controllers/dashboard/milestones_controller_spec.rb b/spec/controllers/dashboard/milestones_controller_spec.rb
index 899aa7a41c1..2d41bc431ec 100644
--- a/spec/controllers/dashboard/milestones_controller_spec.rb
+++ b/spec/controllers/dashboard/milestones_controller_spec.rb
@@ -65,11 +65,12 @@ RSpec.describe Dashboard::MilestonesController do
expect(response.body).not_to include(project_milestone.title)
end
- it 'shows counts of open and closed group and project milestones to which the user belongs to' do
+ it 'shows counts of open/closed/all group and project milestones to which the user belongs to' do
get :index
- expect(response.body).to include("Open\n<span class=\"badge badge-pill\">2</span>")
- expect(response.body).to include("Closed\n<span class=\"badge badge-pill\">2</span>")
+ expect(response.body).to have_content('Open 2')
+ expect(response.body).to have_content('Closed 2')
+ expect(response.body).to have_content('All 4')
end
context 'external authorization' do
diff --git a/spec/controllers/every_controller_spec.rb b/spec/controllers/every_controller_spec.rb
index a1c377eff76..902872b6e92 100644
--- a/spec/controllers/every_controller_spec.rb
+++ b/spec/controllers/every_controller_spec.rb
@@ -1,24 +1,14 @@
# frozen_string_literal: true
require 'spec_helper'
-
RSpec.describe "Every controller" do
context "feature categories" do
let_it_be(:feature_categories) do
- YAML.load_file(Rails.root.join('config', 'feature_categories.yml')).map(&:to_sym).to_set
+ Gitlab::FeatureCategories.default.categories.map(&:to_sym).to_set
end
let_it_be(:controller_actions) do
- # This will return tuples of all controller actions defined in the routes
- # Only for controllers inheriting ApplicationController
- # Excluding controllers from gems (OAuth, Sidekiq)
- Rails.application.routes.routes
- .map { |route| route.required_defaults.presence }
- .compact
- .select { |route| route[:controller].present? && route[:action].present? }
- .map { |route| [constantize_controller(route[:controller]), route[:action]] }
- .select { |(controller, action)| controller&.include?(::Gitlab::WithFeatureCategory) }
- .reject { |(controller, action)| controller == ApplicationController || controller == Devise::UnlocksController }
+ Gitlab::RequestEndpoints.all_controller_actions
end
let_it_be(:routes_without_category) do
@@ -74,9 +64,6 @@ RSpec.describe "Every controller" do
end
def actions_defined_in_feature_category_config(controller)
- controller.send(:class_attributes)[:feature_category_config]
- .values
- .flatten
- .map(&:to_s)
+ controller.send(:class_attributes)[:endpoint_attributes_config].defined_actions
end
end
diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb
index aed97a01a72..6e7bcfdaa08 100644
--- a/spec/controllers/graphql_controller_spec.rb
+++ b/spec/controllers/graphql_controller_spec.rb
@@ -38,6 +38,14 @@ RSpec.describe GraphqlController do
sign_in(user)
end
+ it 'sets feature category in ApplicationContext from request' do
+ request.headers["HTTP_X_GITLAB_FEATURE_CATEGORY"] = "web_ide"
+
+ post :execute
+
+ expect(::Gitlab::ApplicationContext.current_context_attribute(:feature_category)).to eq('web_ide')
+ end
+
it 'returns 200 when user can access API' do
post :execute
diff --git a/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb b/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb
index 7415c2860c8..fa402d556c7 100644
--- a/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb
+++ b/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe Groups::DependencyProxyForContainersController do
include HttpBasicAuthHelpers
include DependencyProxyHelpers
+ include WorkhorseHelpers
let_it_be(:user) { create(:user) }
let_it_be_with_reload(:group) { create(:group, :private) }
@@ -242,16 +243,9 @@ RSpec.describe Groups::DependencyProxyForContainersController do
end
describe 'GET #blob' do
- let_it_be(:blob) { create(:dependency_proxy_blob) }
+ let(:blob) { create(:dependency_proxy_blob, group: group) }
let(:blob_sha) { blob.file_name.sub('.gz', '') }
- let(:blob_response) { { status: :success, blob: blob, from_cache: false } }
-
- before do
- allow_next_instance_of(DependencyProxy::FindOrCreateBlobService) do |instance|
- allow(instance).to receive(:execute).and_return(blob_response)
- end
- end
subject { get_blob }
@@ -264,40 +258,31 @@ RSpec.describe Groups::DependencyProxyForContainersController do
it_behaves_like 'without permission'
it_behaves_like 'feature flag disabled with private group'
- context 'remote blob request fails' do
- let(:blob_response) do
- {
- status: :error,
- http_status: 400,
- message: ''
- }
- end
-
- before do
- group.add_guest(user)
- end
-
- it 'proxies status from the remote blob request', :aggregate_failures do
- subject
-
- expect(response).to have_gitlab_http_status(:bad_request)
- expect(response.body).to be_empty
- end
- end
-
context 'a valid user' do
before do
group.add_guest(user)
end
it_behaves_like 'a successful blob pull'
- it_behaves_like 'a package tracking event', described_class.name, 'pull_blob'
+ it_behaves_like 'a package tracking event', described_class.name, 'pull_blob_from_cache'
- context 'with a cache entry' do
- let(:blob_response) { { status: :success, blob: blob, from_cache: true } }
+ context 'when cache entry does not exist' do
+ let(:blob_sha) { 'a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4' }
- it_behaves_like 'returning response status', :success
- it_behaves_like 'a package tracking event', described_class.name, 'pull_blob_from_cache'
+ it 'returns Workhorse send-dependency instructions' do
+ subject
+
+ send_data_type, send_data = workhorse_send_data
+ header, url = send_data.values_at('Header', 'Url')
+
+ expect(send_data_type).to eq('send-dependency')
+ expect(header).to eq("Authorization" => ["Bearer abcd1234"])
+ expect(url).to eq(DependencyProxy::Registry.blob_url('alpine', blob_sha))
+ expect(response.headers['Content-Type']).to eq('application/gzip')
+ expect(response.headers['Content-Disposition']).to eq(
+ ActionDispatch::Http::ContentDisposition.format(disposition: 'attachment', filename: blob.file_name)
+ )
+ end
end
end
@@ -319,6 +304,74 @@ RSpec.describe Groups::DependencyProxyForContainersController do
it_behaves_like 'a successful blob pull'
end
end
+
+ context 'when dependency_proxy_workhorse disabled' do
+ let(:blob_response) { { status: :success, blob: blob, from_cache: false } }
+
+ before do
+ stub_feature_flags(dependency_proxy_workhorse: false)
+
+ allow_next_instance_of(DependencyProxy::FindOrCreateBlobService) do |instance|
+ allow(instance).to receive(:execute).and_return(blob_response)
+ end
+ end
+
+ context 'remote blob request fails' do
+ let(:blob_response) do
+ {
+ status: :error,
+ http_status: 400,
+ message: ''
+ }
+ end
+
+ before do
+ group.add_guest(user)
+ end
+
+ it 'proxies status from the remote blob request', :aggregate_failures do
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(response.body).to be_empty
+ end
+ end
+
+ context 'a valid user' do
+ before do
+ group.add_guest(user)
+ end
+
+ it_behaves_like 'a successful blob pull'
+ it_behaves_like 'a package tracking event', described_class.name, 'pull_blob'
+
+ context 'with a cache entry' do
+ let(:blob_response) { { status: :success, blob: blob, from_cache: true } }
+
+ it_behaves_like 'returning response status', :success
+ it_behaves_like 'a package tracking event', described_class.name, 'pull_blob_from_cache'
+ end
+ end
+
+ context 'a valid deploy token' do
+ let_it_be(:user) { create(:deploy_token, :group, :dependency_proxy_scopes) }
+ let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: user, group: group) }
+
+ it_behaves_like 'a successful blob pull'
+
+ context 'pulling from a subgroup' do
+ let_it_be_with_reload(:parent_group) { create(:group) }
+ let_it_be_with_reload(:group) { create(:group, parent: parent_group) }
+
+ before do
+ parent_group.create_dependency_proxy_setting!(enabled: true)
+ group_deploy_token.update_column(:group_id, parent_group.id)
+ end
+
+ it_behaves_like 'a successful blob pull'
+ end
+ end
+ end
end
it_behaves_like 'not found when disabled'
@@ -328,6 +381,61 @@ RSpec.describe Groups::DependencyProxyForContainersController do
end
end
+ describe 'GET #authorize_upload_blob' do
+ let(:blob_sha) { 'a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4' }
+
+ subject(:authorize_upload_blob) do
+ request.headers.merge!(workhorse_internal_api_request_header)
+
+ get :authorize_upload_blob, params: { group_id: group.to_param, image: 'alpine', sha: blob_sha }
+ end
+
+ it_behaves_like 'without permission'
+
+ context 'with a valid user' do
+ before do
+ group.add_guest(user)
+ end
+
+ it 'sends Workhorse file upload instructions', :aggregate_failures do
+ authorize_upload_blob
+
+ expect(response.headers['Content-Type']).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
+ expect(json_response['TempPath']).to eq(DependencyProxy::FileUploader.workhorse_local_upload_path)
+ end
+ end
+ end
+
+ describe 'GET #upload_blob' do
+ let(:blob_sha) { 'a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4' }
+ let(:file) { fixture_file_upload("spec/fixtures/dependency_proxy/#{blob_sha}.gz", 'application/gzip') }
+
+ subject do
+ request.headers.merge!(workhorse_internal_api_request_header)
+
+ get :upload_blob, params: {
+ group_id: group.to_param,
+ image: 'alpine',
+ sha: blob_sha,
+ file: file
+ }
+ end
+
+ it_behaves_like 'without permission'
+
+ context 'with a valid user' do
+ before do
+ group.add_guest(user)
+
+ expect_next_found_instance_of(Group) do |instance|
+ expect(instance).to receive_message_chain(:dependency_proxy_blobs, :create!)
+ end
+ end
+
+ it_behaves_like 'a package tracking event', described_class.name, 'pull_blob'
+ end
+ end
+
def enable_dependency_proxy
group.create_dependency_proxy_setting!(enabled: true)
end
diff --git a/spec/controllers/groups/registry/repositories_controller_spec.rb b/spec/controllers/groups/registry/repositories_controller_spec.rb
index f4541eda293..9ac19b06718 100644
--- a/spec/controllers/groups/registry/repositories_controller_spec.rb
+++ b/spec/controllers/groups/registry/repositories_controller_spec.rb
@@ -19,6 +19,7 @@ RSpec.describe Groups::Registry::RepositoriesController do
before do
stub_container_registry_config(enabled: true)
stub_container_registry_tags(repository: :any, tags: [])
+ stub_container_registry_info
group.add_owner(user)
group.add_guest(guest)
sign_in(user)
@@ -37,6 +38,18 @@ RSpec.describe Groups::Registry::RepositoriesController do
'name' => repo.name
)
end
+
+ [ContainerRegistry::Path::InvalidRegistryPathError, Faraday::Error].each do |error_class|
+ context "when there is a #{error_class}" do
+ it 'displays a connection error message' do
+ expect(::ContainerRegistry::Client).to receive(:registry_info).and_raise(error_class, nil, nil)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
end
shared_examples 'with name parameter' do
@@ -71,6 +84,18 @@ RSpec.describe Groups::Registry::RepositoriesController do
expect(response).to have_gitlab_http_status(:ok)
expect_no_snowplow_event
end
+
+ [ContainerRegistry::Path::InvalidRegistryPathError, Faraday::Error].each do |error_class|
+ context "when there is an invalid path error #{error_class}" do
+ it 'displays a connection error message' do
+ expect(::ContainerRegistry::Client).to receive(:registry_info).and_raise(error_class, nil, nil)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
end
context 'json format' do
diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb
index 599e82afe9b..4e2123c8cc4 100644
--- a/spec/controllers/help_controller_spec.rb
+++ b/spec/controllers/help_controller_spec.rb
@@ -34,14 +34,6 @@ RSpec.describe HelpController do
is_expected.to redirect_to("#{documentation_base_url}/ee/#{path}.html")
end
end
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(help_page_documentation_redirect: false)
- end
-
- it_behaves_like 'documentation pages local render'
- end
end
before do
diff --git a/spec/controllers/import/bulk_imports_controller_spec.rb b/spec/controllers/import/bulk_imports_controller_spec.rb
index 3b2ed2c63ed..3adba32c74a 100644
--- a/spec/controllers/import/bulk_imports_controller_spec.rb
+++ b/spec/controllers/import/bulk_imports_controller_spec.rb
@@ -51,62 +51,87 @@ RSpec.describe Import::BulkImportsController do
end
describe 'GET status' do
+ def get_status(params_override = {})
+ params = { page: 1, per_page: 20, filter: '' }.merge(params_override)
+
+ get :status,
+ params: params,
+ format: :json,
+ session: {
+ bulk_import_gitlab_url: 'https://gitlab.example.com',
+ bulk_import_gitlab_access_token: 'demo-pat'
+ }
+ end
+
+ include_context 'bulk imports requests context', 'https://gitlab.example.com'
+
let(:client) { BulkImports::Clients::HTTP.new(url: 'http://gitlab.example', token: 'token') }
+ let(:version) { "#{BulkImport::MIN_MAJOR_VERSION}.#{BulkImport::MIN_MINOR_VERSION_FOR_PROJECT}.0" }
+ let(:version_response) { double(code: 200, success?: true, parsed_response: { 'version' => version }) }
describe 'serialized group data' do
- let(:client_response) do
+ let(:expected_response) do
double(
parsed_response: [
- { 'id' => 1, 'full_name' => 'group1', 'full_path' => 'full/path/group1', 'web_url' => 'http://demo.host/full/path/group1' },
- { 'id' => 2, 'full_name' => 'group2', 'full_path' => 'full/path/group2', 'web_url' => 'http://demo.host/full/path/group1' }
+ {
+ "full_name" => "Stub",
+ "full_path" => "stub-group",
+ "id" => 2595438,
+ "web_url" => "https://gitlab.com/groups/auto-breakfast"
+ }
],
headers: {
'x-next-page' => '2',
'x-page' => '1',
'x-per-page' => '20',
- 'x-total' => '37',
+ 'x-total' => '42',
'x-total-pages' => '2'
}
)
end
- let(:client_params) do
- {
- top_level_only: true,
- min_access_level: Gitlab::Access::OWNER
- }
- end
-
- before do
- allow(controller).to receive(:client).and_return(client)
- allow(client).to receive(:get).with('groups', client_params).and_return(client_response)
- end
-
it 'returns serialized group data' do
- get :status, format: :json
+ get_status
+
+ version_validation = {
+ "features" => {
+ "project_migration" => {
+ "available" => true,
+ "min_version" => BulkImport.min_gl_version_for_project_migration.to_s
+ },
+ "source_instance_version" => version
+ }
+ }
- expect(json_response).to eq({ importable_data: client_response.parsed_response }.as_json)
+ expect(json_response).to include("importable_data" => expected_response.parsed_response, "version_validation" => hash_including(version_validation))
end
it 'forwards pagination headers' do
- get :status, format: :json
-
- expect(response.headers['x-per-page']).to eq client_response.headers['x-per-page']
- expect(response.headers['x-page']).to eq client_response.headers['x-page']
- expect(response.headers['x-next-page']).to eq client_response.headers['x-next-page']
- expect(response.headers['x-prev-page']).to eq client_response.headers['x-prev-page']
- expect(response.headers['x-total']).to eq client_response.headers['x-total']
- expect(response.headers['x-total-pages']).to eq client_response.headers['x-total-pages']
+ get_status
+
+ expect(response.headers['x-per-page']).to eq expected_response.headers['x-per-page']
+ expect(response.headers['x-page']).to eq expected_response.headers['x-page']
+ expect(response.headers['x-next-page']).to eq expected_response.headers['x-next-page']
+ expect(response.headers['x-prev-page']).to eq expected_response.headers['x-prev-page']
+ expect(response.headers['x-total']).to eq expected_response.headers['x-total']
+ expect(response.headers['x-total-pages']).to eq expected_response.headers['x-total-pages']
end
context 'when filtering' do
- it 'returns filtered result' do
- filter = 'test'
- search_params = client_params.merge(search: filter)
+ let_it_be(:filter) { 'test' }
- expect(client).to receive(:get).with('groups', search_params).and_return(client_response)
+ let(:client_params) do
+ {
+ top_level_only: true,
+ min_access_level: Gitlab::Access::OWNER,
+ search: filter
+ }
+ end
+
+ it 'returns filtered result' do
+ get_status(filter: filter)
- get :status, format: :json, params: { filter: filter }
+ expect(json_response['importable_data'].first['full_name']).to eq('Test')
end
end
end
@@ -148,18 +173,19 @@ RSpec.describe Import::BulkImportsController do
context 'when connection error occurs' do
before do
- allow(controller).to receive(:client).and_return(client)
- allow(client).to receive(:get).and_raise(BulkImports::Error)
+ allow_next_instance_of(BulkImports::Clients::HTTP) do |instance|
+ allow(instance).to receive(:get).and_raise(BulkImports::Error)
+ end
end
it 'returns 422' do
- get :status, format: :json
+ get_status
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
it 'clears session' do
- get :status, format: :json
+ get_status
expect(session[:gitlab_url]).to be_nil
expect(session[:gitlab_access_token]).to be_nil
@@ -199,9 +225,9 @@ RSpec.describe Import::BulkImportsController do
session[:bulk_import_gitlab_url] = instance_url
end
- it 'executes BulkImportService' do
+ it 'executes BulkImpors::CreatetService' do
expect_next_instance_of(
- BulkImportService, user, bulk_import_params, { url: instance_url, access_token: pat }) do |service|
+ ::BulkImports::CreateService, user, bulk_import_params, { url: instance_url, access_token: pat }) do |service|
allow(service).to receive(:execute).and_return(ServiceResponse.success(payload: bulk_import))
end
@@ -214,7 +240,7 @@ RSpec.describe Import::BulkImportsController do
it 'returns error when validation fails' do
error_response = ServiceResponse.error(message: 'Record invalid', http_status: :unprocessable_entity)
expect_next_instance_of(
- BulkImportService, user, bulk_import_params, { url: instance_url, access_token: pat }) do |service|
+ ::BulkImports::CreateService, user, bulk_import_params, { url: instance_url, access_token: pat }) do |service|
allow(service).to receive(:execute).and_return(error_response)
end
diff --git a/spec/controllers/jira_connect/app_descriptor_controller_spec.rb b/spec/controllers/jira_connect/app_descriptor_controller_spec.rb
index 25c11d92b4e..9d890efdd33 100644
--- a/spec/controllers/jira_connect/app_descriptor_controller_spec.rb
+++ b/spec/controllers/jira_connect/app_descriptor_controller_spec.rb
@@ -46,7 +46,8 @@ RSpec.describe JiraConnect::AppDescriptorController do
apiVersion: 1,
apiMigrations: {
'context-qsh': true,
- gdpr: true
+ gdpr: true,
+ 'signed-install': true
}
)
@@ -89,5 +90,17 @@ RSpec.describe JiraConnect::AppDescriptorController do
)
)
end
+
+ context 'when jira_connect_asymmetric_jwt is disabled' do
+ before do
+ stub_feature_flags(jira_connect_asymmetric_jwt: false)
+ end
+
+ specify do
+ get :show
+
+ expect(json_response).to include('apiMigrations' => include('signed-install' => false))
+ end
+ end
end
end
diff --git a/spec/controllers/jira_connect/events_controller_spec.rb b/spec/controllers/jira_connect/events_controller_spec.rb
index e9fecb594a7..78bd0dc8318 100644
--- a/spec/controllers/jira_connect/events_controller_spec.rb
+++ b/spec/controllers/jira_connect/events_controller_spec.rb
@@ -3,9 +3,49 @@
require 'spec_helper'
RSpec.describe JiraConnect::EventsController do
+ shared_examples 'verifies asymmetric JWT token' do
+ context 'when token is valid' do
+ include_context 'valid JWT token'
+
+ it 'renders successful' do
+ send_request
+
+ expect(response).to have_gitlab_http_status(:success)
+ end
+ end
+
+ context 'when token is invalid' do
+ include_context 'invalid JWT token'
+
+ it 'renders unauthorized' do
+ send_request
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+ end
+
+ shared_context 'valid JWT token' do
+ before do
+ allow_next_instance_of(Atlassian::JiraConnect::AsymmetricJwt) do |asymmetric_jwt|
+ allow(asymmetric_jwt).to receive(:valid?).and_return(true)
+ allow(asymmetric_jwt).to receive(:iss_claim).and_return(client_key)
+ end
+ end
+ end
+
+ shared_context 'invalid JWT token' do
+ before do
+ allow_next_instance_of(Atlassian::JiraConnect::AsymmetricJwt) do |asymmetric_jwt|
+ allow(asymmetric_jwt).to receive(:valid?).and_return(false)
+ end
+ end
+ end
+
describe '#installed' do
let(:client_key) { '1234' }
let(:shared_secret) { 'secret' }
+
let(:params) do
{
clientKey: client_key,
@@ -14,10 +54,16 @@ RSpec.describe JiraConnect::EventsController do
}
end
+ include_context 'valid JWT token'
+
subject do
post :installed, params: params
end
+ it_behaves_like 'verifies asymmetric JWT token' do
+ let(:send_request) { subject }
+ end
+
it 'saves the jira installation data' do
expect { subject }.to change { JiraConnectInstallation.count }.by(1)
end
@@ -31,13 +77,15 @@ RSpec.describe JiraConnect::EventsController do
expect(installation.base_url).to eq('https://test.atlassian.net')
end
- context 'client key already exists' do
- it 'returns 422' do
- create(:jira_connect_installation, client_key: client_key)
+ context 'when jira_connect_asymmetric_jwt is disabled' do
+ before do
+ stub_feature_flags(jira_connect_asymmetric_jwt: false)
+ end
- subject
+ it 'saves the jira installation data without JWT validation' do
+ expect(Atlassian::JiraConnect::AsymmetricJwt).not_to receive(:new)
- expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect { subject }.to change { JiraConnectInstallation.count }.by(1)
end
end
@@ -49,27 +97,68 @@ RSpec.describe JiraConnect::EventsController do
}
end
- it 'validates the JWT token in authorization header and returns 200 without creating a new installation' do
- create(:jira_connect_installation, client_key: client_key, shared_secret: shared_secret)
- request.headers["Authorization"] = "Bearer #{Atlassian::Jwt.encode({ iss: client_key }, shared_secret)}"
+ it 'returns 422' do
+ subject
- expect { subject }.not_to change { JiraConnectInstallation.count }
- expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
- end
- describe '#uninstalled' do
- let!(:installation) { create(:jira_connect_installation) }
- let(:qsh) { Atlassian::Jwt.create_query_string_hash('https://gitlab.test/events/uninstalled', 'POST', 'https://gitlab.test') }
+ context 'and an installation exists' do
+ let!(:installation) { create(:jira_connect_installation, client_key: client_key, shared_secret: shared_secret) }
- before do
- request.headers['Authorization'] = "JWT #{auth_token}"
+ it 'validates the JWT token in authorization header and returns 200 without creating a new installation' do
+ expect { subject }.not_to change { JiraConnectInstallation.count }
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ context 'when jira_connect_asymmetric_jwt is disabled' do
+ before do
+ stub_feature_flags(jira_connect_asymmetric_jwt: false)
+ end
+
+ it 'decodes the JWT token in authorization header and returns 200 without creating a new installation' do
+ request.headers["Authorization"] = "Bearer #{Atlassian::Jwt.encode({ iss: client_key }, shared_secret)}"
+
+ expect(Atlassian::JiraConnect::AsymmetricJwt).not_to receive(:new)
+
+ expect { subject }.not_to change { JiraConnectInstallation.count }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
end
+ end
+ end
+
+ describe '#uninstalled' do
+ let_it_be(:installation) { create(:jira_connect_installation) }
+
+ let(:client_key) { installation.client_key }
+ let(:params) do
+ {
+ clientKey: client_key,
+ baseUrl: 'https://test.atlassian.net'
+ }
+ end
+
+ it_behaves_like 'verifies asymmetric JWT token' do
+ let(:send_request) { post :uninstalled, params: params }
+ end
+
+ subject(:post_uninstalled) { post :uninstalled, params: params }
- subject(:post_uninstalled) { post :uninstalled }
+ context 'when JWT is invalid' do
+ include_context 'invalid JWT token'
- context 'when JWT is invalid' do
- let(:auth_token) { 'invalid_token' }
+ it 'does not delete the installation' do
+ expect { post_uninstalled }.not_to change { JiraConnectInstallation.count }
+ end
+
+ context 'when jira_connect_asymmetric_jwt is disabled' do
+ before do
+ stub_feature_flags(jira_connect_asymmetric_jwt: false)
+ request.headers['Authorization'] = 'JWT invalid token'
+ end
it 'returns 403' do
post_uninstalled
@@ -81,14 +170,42 @@ RSpec.describe JiraConnect::EventsController do
expect { post_uninstalled }.not_to change { JiraConnectInstallation.count }
end
end
+ end
+
+ context 'when JWT is valid' do
+ include_context 'valid JWT token'
+
+ let(:jira_base_path) { '/-/jira_connect' }
+ let(:jira_event_path) { '/-/jira_connect/events/uninstalled' }
+
+ it 'calls the DestroyService and returns ok in case of success' do
+ expect_next_instance_of(JiraConnectInstallations::DestroyService, installation, jira_base_path, jira_event_path) do |destroy_service|
+ expect(destroy_service).to receive(:execute).and_return(true)
+ end
+
+ post_uninstalled
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'calls the DestroyService and returns unprocessable_entity in case of failure' do
+ expect_next_instance_of(JiraConnectInstallations::DestroyService, installation, jira_base_path, jira_event_path) do |destroy_service|
+ expect(destroy_service).to receive(:execute).and_return(false)
+ end
+
+ post_uninstalled
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ end
+
+ context 'when jira_connect_asymmetric_jwt is disabled' do
+ before do
+ stub_feature_flags(jira_connect_asymmetric_jwt: false)
- context 'when JWT is valid' do
- let(:auth_token) do
- Atlassian::Jwt.encode({ iss: installation.client_key, qsh: qsh }, installation.shared_secret)
+ request.headers['Authorization'] = "JWT #{Atlassian::Jwt.encode({ iss: installation.client_key, qsh: qsh }, installation.shared_secret)}"
end
- let(:jira_base_path) { '/-/jira_connect' }
- let(:jira_event_path) { '/-/jira_connect/events/uninstalled' }
+ let(:qsh) { Atlassian::Jwt.create_query_string_hash('https://gitlab.test/events/uninstalled', 'POST', 'https://gitlab.test') }
it 'calls the DestroyService and returns ok in case of success' do
expect_next_instance_of(JiraConnectInstallations::DestroyService, installation, jira_base_path, jira_event_path) do |destroy_service|
diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb
index 9fa90dde997..4f74af295c6 100644
--- a/spec/controllers/metrics_controller_spec.rb
+++ b/spec/controllers/metrics_controller_spec.rb
@@ -67,6 +67,12 @@ RSpec.describe MetricsController, :request_store do
expect(response.body).to match(/^prometheus_counter 1$/)
end
+ it 'initializes the rails request SLIs' do
+ expect(Gitlab::Metrics::RailsSlis).to receive(:initialize_request_slis_if_needed!).and_call_original
+
+ get :index
+ end
+
context 'prometheus metrics are disabled' do
before do
allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(false)
diff --git a/spec/controllers/profiles/two_factor_auths_controller_spec.rb b/spec/controllers/profiles/two_factor_auths_controller_spec.rb
index ca63760d988..e57bd5be937 100644
--- a/spec/controllers/profiles/two_factor_auths_controller_spec.rb
+++ b/spec/controllers/profiles/two_factor_auths_controller_spec.rb
@@ -27,12 +27,6 @@ RSpec.describe Profiles::TwoFactorAuthsController do
expect(flash[:notice])
.to eq _('You need to verify your primary email first before enabling Two-Factor Authentication.')
end
-
- it 'does not redirect when the `ensure_verified_primary_email_for_2fa` feature flag is disabled' do
- stub_feature_flags(ensure_verified_primary_email_for_2fa: false)
-
- expect(response).not_to redirect_to(profile_emails_path)
- end
end
shared_examples 'user must enter a valid current password' do
diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb
index b4019643baf..4959003d788 100644
--- a/spec/controllers/profiles_controller_spec.rb
+++ b/spec/controllers/profiles_controller_spec.rb
@@ -3,7 +3,8 @@
require('spec_helper')
RSpec.describe ProfilesController, :request_store do
- let(:user) { create(:user) }
+ let(:password) { 'longsecret987!' }
+ let(:user) { create(:user, password: password) }
describe 'POST update' do
it 'does not update password' do
@@ -23,7 +24,7 @@ RSpec.describe ProfilesController, :request_store do
sign_in(user)
put :update,
- params: { user: { email: "john@gmail.com", name: "John" } }
+ params: { user: { email: "john@gmail.com", name: "John", validation_password: password } }
user.reload
diff --git a/spec/controllers/projects/alerting/notifications_controller_spec.rb b/spec/controllers/projects/alerting/notifications_controller_spec.rb
index fe0c4ce00bf..2fff8026b22 100644
--- a/spec/controllers/projects/alerting/notifications_controller_spec.rb
+++ b/spec/controllers/projects/alerting/notifications_controller_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Projects::Alerting::NotificationsController do
+ include HttpBasicAuthHelpers
+
let_it_be(:project) { create(:project) }
let_it_be(:environment) { create(:environment, project: project) }
@@ -53,86 +55,96 @@ RSpec.describe Projects::Alerting::NotificationsController do
end
end
- context 'bearer token' do
- context 'when set' do
- context 'when extractable' do
- before do
- request.headers['HTTP_AUTHORIZATION'] = 'Bearer some token'
- end
-
- it 'extracts bearer token' do
- expect(notify_service).to receive(:execute).with('some token', nil)
-
- make_request
- end
-
- context 'with a corresponding integration' do
- context 'with integration parameters specified' do
- let_it_be_with_reload(:integration) { create(:alert_management_http_integration, project: project) }
+ shared_examples 'a working token' do
+ it 'extracts token' do
+ expect(notify_service).to receive(:execute).with('some token', nil)
- let(:params) { project_params(endpoint_identifier: integration.endpoint_identifier, name: integration.name) }
-
- context 'the integration is active' do
- it 'extracts and finds the integration' do
- expect(notify_service).to receive(:execute).with('some token', integration)
+ make_request
+ end
- make_request
- end
- end
+ context 'with a corresponding integration' do
+ context 'with integration parameters specified' do
+ let_it_be_with_reload(:integration) { create(:alert_management_http_integration, project: project) }
- context 'when the integration is inactive' do
- before do
- integration.update!(active: false)
- end
+ let(:params) { project_params(endpoint_identifier: integration.endpoint_identifier, name: integration.name) }
- it 'does not find an integration' do
- expect(notify_service).to receive(:execute).with('some token', nil)
+ context 'the integration is active' do
+ it 'extracts and finds the integration' do
+ expect(notify_service).to receive(:execute).with('some token', integration)
- make_request
- end
- end
+ make_request
end
+ end
- context 'without integration parameters specified' do
- let_it_be(:integration) { create(:alert_management_http_integration, :legacy, project: project) }
+ context 'when the integration is inactive' do
+ before do
+ integration.update!(active: false)
+ end
- it 'extracts and finds the legacy integration' do
- expect(notify_service).to receive(:execute).with('some token', integration)
+ it 'does not find an integration' do
+ expect(notify_service).to receive(:execute).with('some token', nil)
- make_request
- end
+ make_request
end
end
end
- context 'when inextractable' do
- it 'passes nil for a non-bearer token' do
- request.headers['HTTP_AUTHORIZATION'] = 'some token'
+ context 'without integration parameters specified' do
+ let_it_be(:integration) { create(:alert_management_http_integration, :legacy, project: project) }
- expect(notify_service).to receive(:execute).with(nil, nil)
+ it 'extracts and finds the legacy integration' do
+ expect(notify_service).to receive(:execute).with('some token', integration)
make_request
end
end
end
+ end
- context 'when missing' do
- it 'passes nil' do
- expect(notify_service).to receive(:execute).with(nil, nil)
-
- make_request
+ context 'with bearer token' do
+ context 'when set' do
+ before do
+ request.headers.merge(build_token_auth_header('some token'))
end
+
+ it_behaves_like 'a working token'
+ end
+ end
+
+ context 'with basic auth token' do
+ before do
+ request.headers.merge basic_auth_header(nil, 'some token')
+ end
+
+ it_behaves_like 'a working token'
+ end
+
+ context 'when inextractable token' do
+ it 'passes nil for a non-bearer token' do
+ request.headers['HTTP_AUTHORIZATION'] = 'some token'
+
+ expect(notify_service).to receive(:execute).with(nil, nil)
+
+ make_request
+ end
+ end
+
+ context 'when missing token' do
+ it 'passes nil' do
+ expect(notify_service).to receive(:execute).with(nil, nil)
+
+ make_request
end
end
end
- context 'generic alert payload' do
+ context 'with generic alert payload' do
it_behaves_like 'process alert payload', Projects::Alerting::NotifyService do
let(:payload) { { title: 'Alert title' } }
end
end
- context 'Prometheus alert payload' do
+ context 'with Prometheus alert payload' do
include PrometheusHelpers
it_behaves_like 'process alert payload', Projects::Prometheus::Alerts::NotifyService do
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index a00e302a64f..43e8bbd83cf 100644
--- a/spec/controllers/projects/branches_controller_spec.rb
+++ b/spec/controllers/projects/branches_controller_spec.rb
@@ -239,7 +239,7 @@ RSpec.describe Projects::BranchesController do
end
end
- context 'without issue feature access' do
+ context 'without issue feature access', :sidekiq_inline do
before do
project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE)
@@ -656,6 +656,26 @@ RSpec.describe Projects::BranchesController do
)
end
end
+
+ context 'when gitaly is not available' do
+ before do
+ allow_next_instance_of(Gitlab::GitalyClient::RefService) do |ref_service|
+ allow(ref_service).to receive(:local_branches).and_raise(GRPC::DeadlineExceeded)
+ end
+
+ get :index, format: :html, params: {
+ namespace_id: project.namespace, project_id: project
+ }
+ end
+
+ it 'returns with a status 200' do
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'sets gitaly_unavailable variable' do
+ expect(assigns[:gitaly_unavailable]).to be_truthy
+ end
+ end
end
describe 'GET diverging_commit_counts' do
diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb
index 2412b970342..48afd42e8ff 100644
--- a/spec/controllers/projects/compare_controller_spec.rb
+++ b/spec/controllers/projects/compare_controller_spec.rb
@@ -409,7 +409,7 @@ RSpec.describe Projects::CompareController do
end
end
- context 'when the user does not have access to the project' do
+ context 'when the user does not have access to the project', :sidekiq_inline do
before do
project.team.truncate
project.update!(visibility: 'private')
diff --git a/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb b/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb
index 56c0ef592ca..cc0f4a426f4 100644
--- a/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb
+++ b/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb
@@ -91,7 +91,7 @@ RSpec.describe Projects::DesignManagement::Designs::ResizedImageController do
# (the record that represents the design at a specific version), to
# verify that the correct file is being returned.
def etag(action)
- ActionDispatch::TestResponse.new.send(:generate_weak_etag, [action.cache_key, ''])
+ ActionDispatch::TestResponse.new.send(:generate_weak_etag, [action.cache_key])
end
specify { expect(newest_version.sha).not_to eq(oldest_version.sha) }
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 977879b453c..0b3bd4d78ac 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -1411,39 +1411,42 @@ RSpec.describe Projects::IssuesController do
stub_application_setting(issues_create_limit: 5)
end
- it 'prevents from creating more issues', :request_store do
- 5.times { post_new_issue }
-
- expect { post_new_issue }
- .to change { Gitlab::GitalyClient.get_request_count }.by(1) # creates 1 projects and 0 issues
-
- post_new_issue
- 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)
- end
-
- it 'logs the event on auth.log' do
- attributes = {
- message: 'Application_Rate_Limiter_Request',
- env: :issues_create_request_limit,
- remote_ip: '0.0.0.0',
- request_method: 'POST',
- path: "/#{project.full_path}/-/issues",
- user_id: user.id,
- username: user.username
- }
+ context 'when issue creation limits imposed' do
+ it 'prevents from creating more issues', :request_store do
+ 5.times { post_new_issue }
- expect(Gitlab::AuthLogger).to receive(:error).with(attributes).once
+ expect { post_new_issue }
+ .to change { Gitlab::GitalyClient.get_request_count }.by(1) # creates 1 projects and 0 issues
- project.add_developer(user)
- sign_in(user)
+ post_new_issue
- 6.times do
- post :create, params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- issue: { title: 'Title', description: 'Description' }
+ 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)
+ end
+
+ it 'logs the event on auth.log' do
+ attributes = {
+ message: 'Application_Rate_Limiter_Request',
+ env: :issues_create_request_limit,
+ remote_ip: '0.0.0.0',
+ request_method: 'POST',
+ path: "/#{project.full_path}/-/issues",
+ user_id: user.id,
+ username: user.username
}
+
+ expect(Gitlab::AuthLogger).to receive(:error).with(attributes).once
+
+ project.add_developer(user)
+ sign_in(user)
+
+ 6.times do
+ post :create, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ issue: { title: 'Title', description: 'Description' }
+ }
+ 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 0da8a30611c..438fc2f2106 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -1876,8 +1876,7 @@ RSpec.describe Projects::MergeRequestsController do
let(:sha) { forked.commit.sha }
let(:environment) { create(:environment, project: forked) }
let(:pipeline) { create(:ci_pipeline, sha: sha, project: forked) }
- let(:build) { create(:ci_build, pipeline: pipeline) }
- let!(:deployment) { create(:deployment, :succeed, environment: environment, sha: sha, ref: 'master', deployable: build) }
+ let!(:build) { create(:ci_build, :with_deployment, environment: environment.name, pipeline: pipeline) }
let(:merge_request) do
create(:merge_request, source_project: forked, target_project: project, target_branch: 'master', head_pipeline: pipeline)
@@ -1901,8 +1900,7 @@ RSpec.describe Projects::MergeRequestsController do
let(:source_environment) { create(:environment, project: project) }
let(:merge_commit_sha) { project.repository.merge(user, forked.commit.id, merge_request, "merged in test") }
let(:post_merge_pipeline) { create(:ci_pipeline, sha: merge_commit_sha, project: project) }
- let(:post_merge_build) { create(:ci_build, pipeline: post_merge_pipeline) }
- let!(:source_deployment) { create(:deployment, :succeed, environment: source_environment, sha: merge_commit_sha, ref: 'master', deployable: post_merge_build) }
+ let!(:post_merge_build) { create(:ci_build, :with_deployment, environment: source_environment.name, pipeline: post_merge_pipeline) }
before do
merge_request.update!(merge_commit_sha: merge_commit_sha)
@@ -1944,9 +1942,6 @@ RSpec.describe Projects::MergeRequestsController do
context 'when a merge request has multiple environments with deployments' do
let(:sha) { merge_request.diff_head_sha }
- let(:ref) { merge_request.source_branch }
-
- let!(:build) { create(:ci_build, pipeline: pipeline) }
let!(:pipeline) { create(:ci_pipeline, sha: sha, project: project) }
let!(:environment) { create(:environment, name: 'env_a', project: project) }
let!(:another_environment) { create(:environment, name: 'env_b', project: project) }
@@ -1954,8 +1949,8 @@ RSpec.describe Projects::MergeRequestsController do
before do
merge_request.update_head_pipeline
- create(:deployment, :succeed, environment: environment, sha: sha, ref: ref, deployable: build)
- create(:deployment, :succeed, environment: another_environment, sha: sha, ref: ref, deployable: build)
+ create(:ci_build, :with_deployment, environment: environment.name, pipeline: pipeline)
+ create(:ci_build, :with_deployment, environment: another_environment.name, pipeline: pipeline)
end
it 'exposes multiple environment statuses' do
diff --git a/spec/controllers/projects/pipeline_schedules_controller_spec.rb b/spec/controllers/projects/pipeline_schedules_controller_spec.rb
index 27a3e95896a..d86f38c1f0b 100644
--- a/spec/controllers/projects/pipeline_schedules_controller_spec.rb
+++ b/spec/controllers/projects/pipeline_schedules_controller_spec.rb
@@ -397,7 +397,7 @@ RSpec.describe Projects::PipelineSchedulesController do
end
end
- describe 'POST #play', :clean_gitlab_redis_cache do
+ describe 'POST #play', :clean_gitlab_redis_rate_limiting do
let(:ref) { 'master' }
before do
diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb
index 2c25c7e20ea..a81173ccaac 100644
--- a/spec/controllers/projects/raw_controller_spec.rb
+++ b/spec/controllers/projects/raw_controller_spec.rb
@@ -84,7 +84,7 @@ RSpec.describe Projects::RawController do
include_examples 'single Gitaly request'
end
- context 'when the endpoint receives requests above the limit', :clean_gitlab_redis_cache do
+ context 'when the endpoint receives requests above the limit', :clean_gitlab_redis_rate_limiting do
let(:file_path) { 'master/README.md' }
before do
diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb
index 0685e5a2055..a5faaaf5969 100644
--- a/spec/controllers/projects/registry/repositories_controller_spec.rb
+++ b/spec/controllers/projects/registry/repositories_controller_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe Projects::Registry::RepositoriesController do
before do
sign_in(user)
stub_container_registry_config(enabled: true)
+ stub_container_registry_info
end
context 'when user has access to registry' do
@@ -30,6 +31,18 @@ RSpec.describe Projects::Registry::RepositoriesController do
expect(response).to have_gitlab_http_status(:not_found)
end
+
+ [ContainerRegistry::Path::InvalidRegistryPathError, Faraday::Error].each do |error_class|
+ context "when there is a #{error_class}" do
+ it 'displays a connection error message' do
+ expect(::ContainerRegistry::Client).to receive(:registry_info).and_raise(error_class, nil, nil)
+
+ go_to_index
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
end
shared_examples 'renders a list of repositories' do
diff --git a/spec/controllers/projects/tags_controller_spec.rb b/spec/controllers/projects/tags_controller_spec.rb
index efb57494f82..d0719643b7f 100644
--- a/spec/controllers/projects/tags_controller_spec.rb
+++ b/spec/controllers/projects/tags_controller_spec.rb
@@ -17,6 +17,25 @@ RSpec.describe Projects::TagsController do
expect(assigns(:tags).map(&:name)).to include('v1.1.0', 'v1.0.0')
end
+ context 'when Gitaly is unavailable' do
+ where(:format) do
+ [:html, :atom]
+ end
+
+ with_them do
+ it 'returns 503 status code' do
+ expect_next_instance_of(TagsFinder) do |finder|
+ expect(finder).to receive(:execute).and_return([[], Gitlab::Git::CommandError.new])
+ end
+
+ get :index, params: { namespace_id: project.namespace.to_param, project_id: project }, format: format
+
+ expect(assigns(:tags)).to eq([])
+ expect(response).to have_gitlab_http_status(:service_unavailable)
+ end
+ end
+ end
+
it 'returns releases matching those tags' do
subject
diff --git a/spec/controllers/projects/usage_quotas_controller_spec.rb b/spec/controllers/projects/usage_quotas_controller_spec.rb
new file mode 100644
index 00000000000..6125ba13f96
--- /dev/null
+++ b/spec/controllers/projects/usage_quotas_controller_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::UsageQuotasController do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, namespace: user.namespace) }
+
+ describe 'GET #index' do
+ render_views
+
+ it 'does not render search settings partial' do
+ sign_in(user)
+ get(:index, params: { namespace_id: user.namespace, project_id: project })
+
+ expect(response).to render_template('index')
+ expect(response).not_to render_template('shared/search_settings')
+ end
+ end
+end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 9d070061850..3d966848c5b 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -312,6 +312,17 @@ RSpec.describe ProjectsController do
expect { get_show }.not_to change { Gitlab::GitalyClient.get_request_count }
end
+
+ it "renders files even with invalid license" do
+ controller.instance_variable_set(:@project, public_project)
+ expect(public_project.repository).to receive(:license_key).and_return('woozle wuzzle').at_least(:once)
+
+ get_show
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('_files')
+ expect(response.body).to have_content('LICENSE') # would be 'MIT license' if stub not works
+ end
end
context "when the url contains .atom" do
@@ -409,42 +420,66 @@ RSpec.describe ProjectsController do
end
describe 'POST create' do
- let!(:params) do
- {
- path: 'foo',
- description: 'bar',
- import_url: project.http_url_to_repo,
- namespace_id: user.namespace.id
- }
- end
-
subject { post :create, params: { project: params } }
before do
sign_in(user)
end
- context 'when import by url is disabled' do
- before do
- stub_application_setting(import_sources: [])
+ context 'on import' do
+ let(:params) do
+ {
+ path: 'foo',
+ description: 'bar',
+ namespace_id: user.namespace.id,
+ import_url: project.http_url_to_repo
+ }
+ end
+
+ context 'when import by url is disabled' do
+ before do
+ stub_application_setting(import_sources: [])
+ end
+
+ it 'does not create project and reports an error' do
+ expect { subject }.not_to change { Project.count }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
end
- it 'does not create project and reports an error' do
- expect { subject }.not_to change { Project.count }
+ context 'when import by url is enabled' do
+ before do
+ stub_application_setting(import_sources: ['git'])
+ end
+
+ it 'creates project' do
+ expect { subject }.to change { Project.count }
- expect(response).to have_gitlab_http_status(:not_found)
+ expect(response).to have_gitlab_http_status(:redirect)
+ end
end
end
- context 'when import by url is enabled' do
- before do
- stub_application_setting(import_sources: ['git'])
+ context 'with new_project_sast_enabled', :experiment do
+ let(:params) do
+ {
+ path: 'foo',
+ description: 'bar',
+ namespace_id: user.namespace.id,
+ initialize_with_sast: '1'
+ }
end
- it 'creates project' do
- expect { subject }.to change { Project.count }
+ it 'tracks an event on project creation' do
+ expect(experiment(:new_project_sast_enabled)).to track(:created,
+ property: 'blank',
+ checked: true,
+ project: an_instance_of(Project),
+ namespace: user.namespace
+ ).on_next_instance.with_context(user: user)
- expect(response).to have_gitlab_http_status(:redirect)
+ post :create, params: { project: params }
end
end
end
@@ -1373,12 +1408,12 @@ RSpec.describe ProjectsController do
end
end
- context 'when the endpoint receives requests above the limit', :clean_gitlab_redis_cache do
+ context 'when the endpoint receives requests above the limit', :clean_gitlab_redis_rate_limiting do
include_examples 'rate limits project export endpoint'
end
end
- describe '#download_export', :clean_gitlab_redis_cache do
+ describe '#download_export', :clean_gitlab_redis_rate_limiting do
let(:action) { :download_export }
context 'object storage enabled' do
@@ -1413,7 +1448,7 @@ RSpec.describe ProjectsController do
end
end
- context 'when the endpoint receives requests above the limit', :clean_gitlab_redis_cache do
+ context 'when the endpoint receives requests above the limit', :clean_gitlab_redis_rate_limiting do
before do
allow(Gitlab::ApplicationRateLimiter)
.to receive(:increment)
@@ -1485,7 +1520,7 @@ RSpec.describe ProjectsController do
end
end
- context 'when the endpoint receives requests above the limit', :clean_gitlab_redis_cache do
+ context 'when the endpoint receives requests above the limit', :clean_gitlab_redis_rate_limiting do
include_examples 'rate limits project export endpoint'
end
end
diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb
index 5edd60ebc79..a25c597edb2 100644
--- a/spec/controllers/registrations_controller_spec.rb
+++ b/spec/controllers/registrations_controller_spec.rb
@@ -602,6 +602,22 @@ RSpec.describe RegistrationsController do
end
end
+ context 'when user did not accept app terms' do
+ let(:user) { create(:user, accepted_term: nil) }
+
+ before do
+ stub_application_setting(password_authentication_enabled_for_web: false)
+ stub_application_setting(password_authentication_enabled_for_git: false)
+ stub_application_setting(enforce_terms: true)
+ end
+
+ it 'fails with message' do
+ post :destroy, params: { username: user.username }
+
+ expect_failure(s_('Profiles|You must accept the Terms of Service in order to perform this action.'))
+ end
+ end
+
it 'sets the username and caller_id in the context' do
expect(controller).to receive(:destroy).and_wrap_original do |m, *args|
m.call(*args)
diff --git a/spec/controllers/repositories/git_http_controller_spec.rb b/spec/controllers/repositories/git_http_controller_spec.rb
index 04d5008cb34..b5cd14154a3 100644
--- a/spec/controllers/repositories/git_http_controller_spec.rb
+++ b/spec/controllers/repositories/git_http_controller_spec.rb
@@ -7,12 +7,33 @@ RSpec.describe Repositories::GitHttpController do
let_it_be(:personal_snippet) { create(:personal_snippet, :public, :repository) }
let_it_be(:project_snippet) { create(:project_snippet, :public, :repository, project: project) }
+ shared_examples 'handles unavailable Gitaly' do
+ let(:params) { super().merge(service: 'git-upload-pack') }
+
+ before do
+ request.headers.merge! auth_env(user.username, user.password, nil)
+ end
+
+ context 'when Gitaly is unavailable' do
+ it 'responds with a 503 message' do
+ expect(Gitlab::GitalyClient).to receive(:call).and_raise(GRPC::Unavailable)
+
+ get :info_refs, params: params
+
+ expect(response).to have_gitlab_http_status(:service_unavailable)
+ expect(response.body).to eq('The git server, Gitaly, is not available at this time. Please contact your administrator.')
+ end
+ end
+ end
+
context 'when repository container is a project' do
it_behaves_like Repositories::GitHttpController do
let(:container) { project }
let(:user) { project.owner }
let(:access_checker_class) { Gitlab::GitAccess }
+ it_behaves_like 'handles unavailable Gitaly'
+
describe 'POST #git_upload_pack' do
before do
allow(controller).to receive(:verify_workhorse_api!).and_return(true)
@@ -84,6 +105,8 @@ RSpec.describe Repositories::GitHttpController do
let(:container) { personal_snippet }
let(:user) { personal_snippet.author }
let(:access_checker_class) { Gitlab::GitAccessSnippet }
+
+ it_behaves_like 'handles unavailable Gitaly'
end
end
@@ -92,6 +115,8 @@ RSpec.describe Repositories::GitHttpController do
let(:container) { project_snippet }
let(:user) { project_snippet.author }
let(:access_checker_class) { Gitlab::GitAccessSnippet }
+
+ it_behaves_like 'handles unavailable Gitaly'
end
end
end
diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb
index 4e87a9fc1ba..73e8e0c7dd4 100644
--- a/spec/controllers/search_controller_spec.rb
+++ b/spec/controllers/search_controller_spec.rb
@@ -215,6 +215,16 @@ RSpec.describe SearchController do
end
end
+ it 'strips surrounding whitespace from search query' do
+ get :show, params: { scope: 'notes', search: ' foobar ' }
+ expect(assigns[:search_term]).to eq 'foobar'
+ end
+
+ it 'strips surrounding whitespace from autocomplete term' do
+ expect(controller).to receive(:search_autocomplete_opts).with('youcompleteme')
+ get :autocomplete, params: { term: ' youcompleteme ' }
+ end
+
it 'finds issue comments' do
project = create(:project, :public)
note = create(:note_on_issue, project: project)
@@ -305,7 +315,7 @@ RSpec.describe SearchController do
expect(response).to have_gitlab_http_status(:ok)
- expect(response.headers['Cache-Control']).to eq('no-store')
+ expect(response.headers['Cache-Control']).to eq('private, no-store')
end
end
diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb
index 2aa9b86b20e..8442c214cd3 100644
--- a/spec/controllers/uploads_controller_spec.rb
+++ b/spec/controllers/uploads_controller_spec.rb
@@ -599,6 +599,46 @@ RSpec.describe UploadsController do
end
end
+ context "when viewing a topic avatar" do
+ let!(:topic) { create(:topic, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) }
+
+ context "when signed in" do
+ before do
+ sign_in(user)
+ end
+
+ it "responds with status 200" do
+ get :show, params: { model: "projects/topic", mounted_as: "avatar", id: topic.id, filename: "dk.png" }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it_behaves_like 'content publicly cached' do
+ subject do
+ get :show, params: { model: "projects/topic", mounted_as: "avatar", id: topic.id, filename: "dk.png" }
+
+ response
+ end
+ end
+ end
+
+ context "when not signed in" do
+ it "responds with status 200" do
+ get :show, params: { model: "projects/topic", mounted_as: "avatar", id: topic.id, filename: "dk.png" }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it_behaves_like 'content publicly cached' do
+ subject do
+ get :show, params: { model: "projects/topic", mounted_as: "avatar", id: topic.id, filename: "dk.png" }
+
+ response
+ end
+ end
+ end
+ end
+
context 'Appearance' do
context 'when viewing a custom header logo' do
let!(:appearance) { create :appearance, header_logo: fixture_file_upload('spec/fixtures/dk.png', 'image/png') }