Files
gitlab-foss/spec/lib/gitlab/database/dictionary_spec.rb
2025-06-10 06:07:26 +00:00

258 lines
9.0 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Database::Dictionary, feature_category: :database do
subject(:dictionary) { described_class.entries('') }
describe '.entries' do
it 'all tables and views are unique' do
table_and_view_names = dictionary.to_a
table_and_view_names += described_class.entries('views').to_a
# ignore gitlab_internal due to `ar_internal_metadata`, `schema_migrations`
table_and_view_names = table_and_view_names
.reject { |database_dictionary| database_dictionary.schema?('gitlab_internal') }
duplicated_tables = table_and_view_names
.group_by(&:key_name)
.select { |_, schemas| schemas.count > 1 }
.keys
expect(duplicated_tables).to be_empty, \
"Duplicated table(s) #{duplicated_tables.to_a} found in #{described_class}.views_and_tables_to_schema. " \
"Any duplicated table must be removed from db/docs/ or ee/db/docs/. " \
"More info: https://docs.gitlab.com/ee/development/database/database_dictionary.html"
end
it 'builds a Dictionary with validated Entry records' do
expect { dictionary }.not_to raise_error
expect(dictionary).to be_instance_of(described_class)
expect(dictionary).to all(be_instance_of(Gitlab::Database::Dictionary::Entry))
end
end
describe '#to_name_and_schema_mapping' do
it 'returns a hash of name and schema mappings' do
expect(dictionary.to_name_and_schema_mapping).to include(
{
'application_settings' => :gitlab_main_cell_setting,
'members' => :gitlab_main_cell
}
)
end
end
describe '#find_by_table_name' do
it 'finds an entry by table name' do
entry = dictionary.find_by_table_name('application_settings')
expect(entry).to be_instance_of(Gitlab::Database::Dictionary::Entry)
expect(entry.key_name).to eq('application_settings')
expect(entry.gitlab_schema).to eq('gitlab_main_cell_setting')
end
it 'returns nil if the entry is not found' do
entry = dictionary.find_by_table_name('non_existent_table')
expect(entry).to be_nil
end
end
describe '#find_all_by_schema' do
it 'returns an array of entries with a given schema' do
entries = dictionary.find_all_by_schema('gitlab_main_cell')
expect(entries).to all(be_instance_of(Gitlab::Database::Dictionary::Entry))
expect(entries).to all(have_attributes(gitlab_schema: 'gitlab_main_cell'))
end
it 'returns an empty array if no entries match the schema' do
entries = dictionary.find_all_by_schema('non_existent_schema')
expect(entries).to be_empty
end
end
describe '#find_all_having_desired_sharding_key_migration_job' do
it 'returns an array of entries having desired sharding key migration job' do
entries = dictionary.find_all_having_desired_sharding_key_migration_job
expect(entries).to all(be_instance_of(Gitlab::Database::Dictionary::Entry))
expect(entries.map(&:desired_sharding_key_migration_job_name)).to all(be_present)
end
end
describe '.any_entry' do
it 'loads an entry from any scope' do
expect(described_class.any_entry('p_ci_pipelines')).to be_present # Regular table
expect(described_class.any_entry('audit_events_archived')).to be_present # Deleted table
expect(described_class.any_entry('postgres_constraints')).to be_present # View
expect(described_class.any_entry('not_a_table_ever')).to be_nil
end
end
describe '.entry' do
it 'loads an Entry from the given scope' do
expect(described_class.entry('p_ci_pipelines')).to be_present # Regular table
expect(described_class.entry('audit_events_archived')).not_to be_present # Deleted table
expect(described_class.entry('postgres_constraints')).not_to be_present # Deleted table
expect(described_class.entry('audit_events_archived', 'deleted_tables')).to be_present # Deleted table
expect(described_class.entry('postgres_constraints', 'views')).to be_present # View
end
end
describe '::Entry' do
subject(:database_dictionary) { described_class::Entry.new(file_path) }
context 'for a table' do
let(:file_path) { 'db/docs/application_settings.yml' }
describe '#name_and_schema' do
it 'returns the name of the table and its gitlab schema' do
expect(database_dictionary.name_and_schema).to match_array([
'application_settings',
:gitlab_main_cell_setting
])
end
end
describe '#table_name' do
it 'returns the name of the table' do
expect(database_dictionary.table_name).to eq('application_settings')
end
end
describe '#view_name' do
it 'returns nil' do
expect(database_dictionary.view_name).to be_nil
end
end
describe '#milestone' do
it 'returns the milestone in which the table was introduced' do
expect(database_dictionary.milestone).to eq('7.7')
end
end
describe '#milestone_greater_than_or_equal_to?' do
using RSpec::Parameterized::TableSyntax
where(:milestone, :other_milestone, :result) do
'16.9' | '16.10' | false
'16.10' | '16.11' | false
'16.12' | '16.10' | true
'16.11' | '16.10' | true
'16.10' | '16.10' | true
'16.9' | '16.6' | true
'<6.0' | '16.6' | false
'TODO' | '16.6' | false
end
with_them do
before do
allow(database_dictionary).to receive(:milestone).and_return(milestone)
end
it 'returns the right result' do
expect(database_dictionary.milestone_greater_than_or_equal_to?(other_milestone)).to eq(result)
end
end
end
describe '#gitlab_schema' do
it 'returns the gitlab_schema of the table' do
expect(database_dictionary.table_name).to eq('application_settings')
end
end
describe '#table_size' do
it 'returns the table_size of the table' do
expect(database_dictionary.table_size).to eq('small')
end
end
describe '#schema?' do
it 'checks if the given schema matches the schema of the table' do
expect(database_dictionary.schema?('gitlab_main')).to eq(false)
expect(database_dictionary.schema?('gitlab_main_cell_setting')).to eq(true)
end
end
describe '#key_name' do
it 'returns the value of the name of the table' do
expect(database_dictionary.key_name).to eq('application_settings')
end
end
describe '#desired_sharding_key_migration_job_name' do
let(:file_path) { 'db/docs/issue_assignees.yml' }
it 'returns the name of the migration that backfills the desired sharding key' do
expect(database_dictionary.desired_sharding_key_migration_job_name)
.to eq('BackfillIssueAssigneesNamespaceId')
end
end
describe '#validate!' do
it 'raises an error if the gitlab_schema is empty' do
allow(database_dictionary).to receive(:gitlab_schema).and_return(nil)
expect { database_dictionary.validate! }.to raise_error(Gitlab::Database::GitlabSchema::UnknownSchemaError)
end
end
context 'with allow_cross_joins' do
let(:file_path) { 'db/docs/achievements.yml' }
describe '#allow_cross_to_schemas' do
it 'returns the list of allowed schemas' do
expect(database_dictionary.allow_cross_to_schemas(:joins))
.to be_empty
end
end
end
context 'with allow_cross_transactions' do
let(:file_path) { 'db/docs/activity_pub_releases_subscriptions.yml' }
describe '#allow_cross_to_schemas' do
it 'returns the list of allowed schemas' do
expect(database_dictionary.allow_cross_to_schemas(:transactions))
.to be_empty
end
end
end
context 'with allow_cross_foreign_keys' do
let(:file_path) { 'db/docs/agent_group_authorizations.yml' }
describe '#allow_cross_to_schemas' do
it 'returns the list of allowed schemas' do
expect(database_dictionary.allow_cross_to_schemas(:foreign_keys))
.to be_empty
end
end
end
end
context 'for a view' do
let(:file_path) { 'db/docs/views/postgres_constraints.yml' }
describe '#table_name' do
it 'returns nil' do
expect(database_dictionary.table_name).to be_nil
end
end
describe '#view_name' do
it 'returns the name of the view' do
expect(database_dictionary.view_name).to eq('postgres_constraints')
end
end
describe '#key_name' do
it 'returns the value of the name of the view' do
expect(database_dictionary.key_name).to eq('postgres_constraints')
end
end
end
end
end