# frozen_string_literal: true require 'spec_helper' RSpec.describe Gitlab::Current::Organization, feature_category: :organization do using RSpec::Parameterized::TableSyntax let_it_be(:other_organization) { create(:organization) } let_it_be(:organization) { create(:organization) } let_it_be(:user_organization) { create(:organization) } let_it_be(:header_organization) { create(:organization) } let_it_be(:default_organization) { create(:organization, :default) } let_it_be(:group) { create(:group, organization: organization) } let_it_be(:user) { create(:user, organization_users: [create(:organization_user, organization: user_organization)]) } let_it_be(:params_with_namespace_id) { { namespace_id: group.full_path } } let_it_be(:params_with_group_id) { { group_id: group.full_path } } let_it_be(:params_with_groups_id) { { controller: 'groups', id: group.full_path } } let_it_be(:params_with_org_path) { { organization_path: other_organization.path } } let_it_be(:params_with_empty_namespace) { { namespace_id: '' } } let_it_be(:params_with_invalid_namespace) { { namespace_id: 'not_found' } } let_it_be(:params_with_empty_org_path) { { organization_path: '' } } let_it_be(:params_with_invalid_org_path) { { organization_path: 'not_found' } } let_it_be(:params_with_invalid_groups_id) { { controller: 'groups', id: 'not_found' } } let_it_be(:params_with_invalid_group_id) { { group_id: 'not_found' } } let_it_be(:empty_params) { {} } let_it_be(:headers_with_valid_org) { { 'X-GitLab-Organization-ID' => header_organization.id.to_s } } let_it_be(:headers_with_invalid_org) { { 'X-GitLab-Organization-ID' => non_existing_record_id.to_s } } let_it_be(:headers_with_zero) { { 'X-GitLab-Organization-ID' => '0' } } let_it_be(:headers_with_negative) { { 'X-GitLab-Organization-ID' => '-1' } } let_it_be(:headers_with_non_numeric) { { 'X-GitLab-Organization-ID' => 'abc' } } let_it_be(:empty_headers) { {} } let_it_be(:nil_headers) { nil } describe '#organization' do subject(:current_organization) do described_class.new(params: params, user: user_param, headers: headers_param).organization end # rubocop:disable Layout/LineLength -- Parameterized table format requires long lines where(:params, :headers_param, :user_param, :expected, :enables_fallback) do # Valid params take precedence over everything ref(:params_with_namespace_id) | ref(:headers_with_valid_org) | ref(:user) | ref(:organization) | false ref(:params_with_group_id) | ref(:headers_with_valid_org) | ref(:user) | ref(:organization) | false ref(:params_with_groups_id) | ref(:headers_with_valid_org) | ref(:user) | ref(:organization) | false ref(:params_with_org_path) | ref(:headers_with_valid_org) | ref(:user) | ref(:other_organization) | false # Valid params without headers or user ref(:params_with_namespace_id) | ref(:empty_headers) | nil | ref(:organization) | false ref(:params_with_group_id) | ref(:empty_headers) | nil | ref(:organization) | false ref(:params_with_groups_id) | ref(:empty_headers) | nil | ref(:organization) | false ref(:params_with_org_path) | ref(:empty_headers) | nil | ref(:other_organization) | false # Invalid params fall back to headers, then user, then default ref(:params_with_invalid_namespace) | ref(:headers_with_valid_org) | ref(:user) | ref(:header_organization) | false ref(:params_with_invalid_namespace) | ref(:empty_headers) | ref(:user) | ref(:user_organization) | false ref(:params_with_invalid_namespace) | ref(:headers_with_invalid_org) | ref(:user) | ref(:user_organization) | false ref(:params_with_invalid_namespace) | ref(:empty_headers) | nil | ref(:default_organization) | true ref(:params_with_invalid_namespace) | ref(:headers_with_invalid_org) | nil | ref(:default_organization) | true # Empty params follow same fallback chain ref(:empty_params) | ref(:headers_with_valid_org) | ref(:user) | ref(:header_organization) | false ref(:empty_params) | ref(:empty_headers) | ref(:user) | ref(:user_organization) | false ref(:empty_params) | ref(:nil_headers) | ref(:user) | ref(:user_organization) | false ref(:empty_params) | ref(:headers_with_invalid_org) | ref(:user) | ref(:user_organization) | false ref(:empty_params) | ref(:empty_headers) | nil | ref(:default_organization) | true ref(:empty_params) | ref(:nil_headers) | nil | ref(:default_organization) | true ref(:empty_params) | ref(:headers_with_invalid_org) | nil | ref(:default_organization) | true # Test header regex validation - invalid formats should fall back to user/default ref(:empty_params) | ref(:headers_with_zero) | ref(:user) | ref(:user_organization) | false ref(:empty_params) | ref(:headers_with_negative) | ref(:user) | ref(:user_organization) | false ref(:empty_params) | ref(:headers_with_non_numeric) | ref(:user) | ref(:user_organization) | false ref(:empty_params) | ref(:headers_with_zero) | nil | ref(:default_organization) | true # Test other invalid parameter types to ensure consistent fallback behavior ref(:params_with_empty_namespace) | ref(:empty_headers) | nil | ref(:default_organization) | true ref(:params_with_invalid_groups_id) | ref(:headers_with_valid_org) | ref(:user) | ref(:header_organization) | false ref(:params_with_invalid_org_path) | ref(:headers_with_valid_org) | ref(:user) | ref(:header_organization) | false ref(:params_with_invalid_org_path) | ref(:headers_with_invalid_org) | ref(:user) | ref(:user_organization) | false ref(:params_with_invalid_group_id) | ref(:headers_with_invalid_org) | nil | ref(:default_organization) | true end # rubocop:enable Layout/LineLength with_them do it { is_expected.to eq(expected) } it 'sets fallback tracking correctly', :request_store do current_organization expect(Gitlab::Organizations::FallbackOrganizationTracker.enabled?).to eq(enables_fallback) end end context 'for query optimization' do it 'only executes fallback query when namespace_id is empty' do expect { described_class.new(params: params_with_empty_namespace).organization } .to match_query_count(1) # Only the fallback query end it 'only executes fallback query when organization_path is empty' do expect { described_class.new(params: params_with_empty_org_path).organization } .to match_query_count(1) end end end end