Files
gitlab-foss/spec/requests/application_controller_spec.rb
2025-06-06 18:12:15 +00:00

286 lines
8.5 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ApplicationController, type: :request, feature_category: :shared do
let_it_be_with_reload(:user) { create(:user) }
it_behaves_like 'Base action controller' do
before do
sign_in(user)
end
subject(:request) { get root_path }
end
it 'does not send Link header', :use_clean_rails_redis_caching do
sign_in(user)
get root_path
expect(response.headers['Link']).to be_nil
end
describe 'session expiration' do
context 'when user is authenticated' do
it 'sets the redis_expiry option from session_expire_delay setting' do
sign_in(user)
get root_path
expect(request.env['rack.session.options'][:redis_expiry]).to eq(
Settings.gitlab['session_expire_delay'] * 60
)
end
end
context 'when user is unauthenticated' do
it 'sets the redis_expiry option from unauthenticated_session_expire_delay' do
get root_path
expect(request.env['rack.session.options'][:redis_expiry]).to eq(
Settings.gitlab['unauthenticated_session_expire_delay']
)
end
end
end
describe 'unknown route' do
# This spec targets CI environment with precompiled assets to trigger
# Sprockets' `File.binread` and find encoding issues.
#
# See https://gitlab.com/gitlab-com/gl-infra/production/-/issues/17627#note_1782396646
it 'returns 404 even when locale contains UTF-8 chars' do
user.update!(preferred_language: 'ZH-cn')
sign_in(user)
get "/some/undefined/path"
expect(response).to have_gitlab_http_status(:not_found)
expect(response.body.encoding.name).to eq('UTF-8')
end
end
describe 'User-Agent header' do
before do
sign_in(user)
get root_path, headers: { 'User-Agent': user_agent }
end
context 'when missing' do
let(:user_agent) { nil }
it { expect(response).to have_gitlab_http_status(:ok) }
end
context 'when correct' do
let(:user_agent) { 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)' }
it { expect(response).to have_gitlab_http_status(:ok) }
end
context 'when too long' do
let(:user_agent) { 'a' * 3000 }
it { expect(response).to have_gitlab_http_status(:forbidden) }
end
end
describe 'HTTP Router headers' do
before do
sign_in(user)
end
let(:headers) do
{
'X-Gitlab-Http-Router-Rule-Action' => 'classify',
'X-Gitlab-Http-Router-Rule-Type' => 'FIRST_CELL'
}
end
subject(:perform_request) do
get root_path, headers: headers
end
it 'includes the HTTP ROUTER headers in ApplicationContext' do
expect_next_instance_of(RootController) do |controller|
expect(controller).to receive(:index).and_wrap_original do |m, *args|
m.call(*args)
expect(Gitlab::ApplicationContext.current).to include(
'meta.http_router_rule_action' => 'classify',
'meta.http_router_rule_type' => 'FIRST_CELL'
)
end
end
perform_request
end
context 'for counters' do
let(:http_router_rule_counter) { Gitlab::Metrics.counter(:gitlab_http_router_rule_total, 'description') }
context 'when the headers are present' do
context 'for classify action' do
it 'increments the counter' do
expect { perform_request }.to change {
http_router_rule_counter.get(rule_action: 'classify', rule_type: 'FIRST_CELL')
}.by(1)
end
end
context 'for classify action by SESSION_PREFIX' do
let(:headers) do
{
'X-Gitlab-Http-Router-Rule-Action' => 'classify',
'X-Gitlab-Http-Router-Rule-Type' => 'SESSION_PREFIX'
}
end
it 'increments the counter with labels' do
expect { perform_request }.to change {
http_router_rule_counter.get(rule_action: 'classify', rule_type: 'SESSION_PREFIX')
}.by(1)
end
end
context 'for classify action by CELL_ID' do
let(:headers) do
{
'X-Gitlab-Http-Router-Rule-Action' => 'classify',
'X-Gitlab-Http-Router-Rule-Type' => 'CELL_ID'
}
end
it 'increments the counter with labels' do
expect { perform_request }.to change {
http_router_rule_counter.get(rule_action: 'classify', rule_type: 'CELL_ID')
}.by(1)
end
end
context 'for proxy action' do
let(:headers) do
{
'X-Gitlab-Http-Router-Rule-Action' => 'proxy'
}
end
it 'increments the counter' do
expect { perform_request }.to change {
http_router_rule_counter.get(rule_action: 'proxy', rule_type: nil)
}.by(1)
end
end
context 'for invalid action and type' do
let(:headers) do
{
'X-Gitlab-Http-Router-Rule-Action' => 'invalid',
'X-Gitlab-Http-Router-Rule-Type' => 'invalid'
}
end
it 'does not increment the counter' do
expect { perform_request }.to change {
http_router_rule_counter.get(rule_action: 'invalid', rule_type: 'invalid')
}.by(0)
end
end
context 'when action is not present and type is present' do
let(:headers) do
{
'X-Gitlab-Http-Router-Rule-Type' => 'FIRST_CELL'
}
end
it 'does not increment the counter' do
expect { perform_request }.to change {
http_router_rule_counter.get(rule_action: nil, rule_type: 'FIRST_CELL')
}.by(0)
end
end
end
context 'when the headers are absent' do
let(:headers) { {} }
it 'does not increment the counter' do
expect { perform_request }.to change {
http_router_rule_counter.get(rule_action: nil, rule_type: nil)
}.by(0)
end
end
end
end
describe 'static context middleware', feature_category: :error_budgets do
# to check the middleware tests, go to spec/lib/gitlab/middleware/static_context_middleware_spec.rb
let(:expected_context) do
{ 'meta.feature_category' => 'groups_and_projects',
'meta.caller_id' => 'Dashboard::GroupsController#index' }
end
context 'when action is successfully called' do
it 'pushes static context to current context' do
context = {}
allow_next_instance_of(Dashboard::GroupsController) do |_controller|
context.merge!(Gitlab::ApplicationContext.current.to_h)
end
get '/dashboard/groups' # randomly picked route
expect(response).to have_gitlab_http_status(:found)
expect(context).to include expected_context
end
end
context 'when an exception is thrown before action' do
it 'pushes static context to current context before controller callbacks' do
context = {}
unexpected_error = 'boom 💣💥'
allow_next_instance_of(Dashboard::GroupsController) do |controller|
# picking up a random before_action method to raise an "unexpected" exception
allow(controller).to receive(:authenticate_user!).and_raise(unexpected_error)
context.merge!(Gitlab::ApplicationContext.current.to_h)
end
expect { get '/dashboard/groups' }.to raise_error(unexpected_error)
expect(context).to include expected_context
end
end
context 'when controller overrides feature_category with nil' do
it 'ignores nil feature category override' do
context = {}
allow_next_instance_of(Projects::NotesController) do |controller|
# mimicking a bug overriding feature_category with nil
allow(controller).to receive(:feature_category).and_return(nil)
context.merge!(Gitlab::ApplicationContext.current.to_h)
end
project = create(:project, :public)
project_snippet = create(:project_snippet, project: project)
create(:note_on_project_snippet, project: project, noteable: project_snippet)
# picking a route targeting a controller that overrides feature_category
get project_noteable_notes_path(
project,
target_type: 'project_snippet',
target_id: project_snippet.id,
html: true
)
expect(context).to include({ 'meta.feature_category' => 'team_planning' })
end
end
end
end