diff options
author | Kamil Trzciński <ayufan@ayufan.eu> | 2018-10-30 16:03:57 +0100 |
---|---|---|
committer | Kamil Trzciński <ayufan@ayufan.eu> | 2018-11-15 12:51:15 +0100 |
commit | 90801a43ca69462d7cd39e64c2eee6e871c03111 (patch) | |
tree | 585b6e4d42ae8cd35b67a64e8f43dac4d96f6b18 /spec/db | |
parent | 321506c7431788e23e12a196ee1b77c0af2ea5f6 (diff) | |
download | gitlab-ce-90801a43ca69462d7cd39e64c2eee6e871c03111.tar.gz |
Validate foreign keys being indexed
Diffstat (limited to 'spec/db')
-rw-r--r-- | spec/db/schema_spec.rb | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb new file mode 100644 index 00000000000..43e23ee389e --- /dev/null +++ b/spec/db/schema_spec.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Database schema' do + let(:connection) { ActiveRecord::Base.connection } + let(:tables) { connection.tables } + + # Use if you are certain that this column should not have a foreign key + IGNORED_FK_COLUMNS = { + abuse_reports: %w[reporter_id user_id], + application_settings: %w[performance_bar_allowed_group_id], + audit_events: %w[author_id entity_id], + award_emoji: %w[awardable_id user_id], + chat_names: %w[chat_id service_id team_id user_id], + chat_teams: %w[team_id], + ci_builds: %w[erased_by_id runner_id trigger_request_id user_id], + ci_pipelines: %w[user_id], + ci_runner_projects: %w[runner_id], + ci_trigger_requests: %w[commit_id], + cluster_providers_gcp: %w[gcp_project_id operation_id], + deploy_keys_projects: %w[deploy_key_id], + deployments: %w[deployable_id environment_id user_id], + emails: %w[user_id], + events: %w[target_id], + forked_project_links: %w[forked_from_project_id], + identities: %w[user_id], + issues: %w[last_edited_by_id], + keys: %w[user_id], + label_links: %w[target_id], + lfs_objects_projects: %w[lfs_object_id project_id], + members: %w[source_id created_by_id], + merge_requests: %w[last_edited_by_id], + namespaces: %w[owner_id parent_id], + notes: %w[author_id commit_id noteable_id updated_by_id resolved_by_id discussion_id], + notification_settings: %w[source_id], + oauth_access_grants: %w[resource_owner_id application_id], + oauth_access_tokens: %w[resource_owner_id application_id], + oauth_applications: %w[owner_id], + project_group_links: %w[group_id], + project_statistics: %w[namespace_id], + projects: %w[creator_id namespace_id ci_id], + redirect_routes: %w[source_id], + repository_languages: %w[programming_language_id], + routes: %w[source_id], + sent_notifications: %w[project_id noteable_id recipient_id commit_id in_reply_to_discussion_id], + snippets: %w[author_id], + spam_logs: %w[user_id], + subscriptions: %w[user_id subscribable_id], + taggings: %w[tag_id taggable_id tagger_id], + timelogs: %w[user_id], + todos: %w[target_id commit_id], + uploads: %w[model_id], + user_agent_details: %w[subject_id], + users: %w[color_scheme_id created_by_id theme_id], + users_star_projects: %w[user_id], + web_hooks: %w[service_id] + }.with_indifferent_access.freeze + + context 'for table' do + ActiveRecord::Base.connection.tables.sort.each do |table| + describe table do + let(:indexes) { connection.indexes(table) } + let(:columns) { connection.columns(table) } + let(:foreign_keys) { connection.foreign_keys(table) } + + context 'all foreign keys' do + # for index to be effective, the FK constraint has to be at first place + it 'are indexed' do + first_indexed_column = indexes.map(&:columns).map(&:first) + foreign_keys_columns = foreign_keys.map(&:column) + + expect(first_indexed_column.uniq).to include(*foreign_keys_columns) + end + end + + context 'columns ending with _id' do + let(:column_names) { columns.map(&:name) } + let(:column_names_with_id) { column_names.select { |column_name| column_name.ends_with?('_id') } } + let(:foreign_keys_columns) { foreign_keys.map(&:column) } + let(:ignored_columns) { IGNORED_FK_COLUMNS[table] || [] } + + it 'do have the foreign keys' do + expect(column_names_with_id - ignored_columns).to contain_exactly(*foreign_keys_columns) + end + end + end + end + end +end |