gitlab-ce/spec/lib/gitlab/database/migration_helpers/swapping_spec.rb

173 lines
5.3 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Database::MigrationHelpers::Swapping, feature_category: :database do
let(:connection) { ApplicationRecord.connection }
let(:migration_context) do
ActiveRecord::Migration
.new
.extend(described_class)
.extend(Gitlab::Database::MigrationHelpers)
end
let(:service_instance) { instance_double('Gitlab::Database::Migrations::SwapColumns', execute: nil) }
describe '#reset_trigger_function' do
let(:trigger_function_name) { 'existing_trigger_function' }
before do
connection.execute(<<~SQL)
CREATE FUNCTION #{trigger_function_name}() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
NEW."bigint_column" := NEW."integer_column";
RETURN NEW;
END;
$$;
SQL
end
it 'resets' do
recorder = ActiveRecord::QueryRecorder.new do
migration_context.reset_trigger_function(trigger_function_name)
end
expect(recorder.log).to include(/ALTER FUNCTION "existing_trigger_function" RESET ALL/)
end
end
describe '#swap_columns' do
let(:table) { :ci_pipeline_variables }
let(:column1) { :pipeline_id }
let(:column2) { :pipeline_id_convert_to_bigint }
it 'calls service' do
expect(::Gitlab::Database::Migrations::SwapColumns).to receive(:new).with(
migration_context: migration_context,
table: table,
column1: column1,
column2: column2
).and_return(service_instance)
migration_context.swap_columns(table, column1, column2)
end
end
describe '#swap_columns_default' do
let(:table) { :_test_table }
let(:column1) { :pipeline_id }
let(:column2) { :pipeline_id_convert_to_bigint }
it 'calls service' do
expect(::Gitlab::Database::Migrations::SwapColumnsDefault).to receive(:new).with(
migration_context: migration_context,
table: table,
column1: column1,
column2: column2
).and_return(service_instance)
migration_context.swap_columns_default(table, column1, column2)
end
end
describe '#swap_foreign_keys' do
let(:table) { :_test_swap_foreign_keys }
let(:referenced_table) { "#{table}_referenced" }
let(:foreign_key1) { :fkey_on_integer_column }
let(:foreign_key2) { :fkey_on_bigint_column }
before do
connection.execute(<<~SQL)
CREATE TABLE #{table} (
integer_column integer NOT NULL,
bigint_column bigint DEFAULT 0 NOT NULL
);
CREATE TABLE #{referenced_table} (
id bigint NOT NULL
);
ALTER TABLE ONLY #{referenced_table}
ADD CONSTRAINT pk PRIMARY KEY (id);
ALTER TABLE ONLY #{table}
ADD CONSTRAINT #{foreign_key1}
FOREIGN KEY (integer_column) REFERENCES #{referenced_table}(id) ON DELETE SET NULL;
ALTER TABLE ONLY #{table}
ADD CONSTRAINT #{foreign_key2}
FOREIGN KEY (bigint_column) REFERENCES #{referenced_table}(id) ON DELETE SET NULL;
SQL
end
shared_examples_for 'swapping foreign keys correctly' do
specify do
expect { migration_context.swap_foreign_keys(table, foreign_key1, foreign_key2) }
.to change {
find_foreign_key_by(foreign_key1).options[:column]
}.from('integer_column').to('bigint_column')
.and change {
find_foreign_key_by(foreign_key2).options[:column]
}.from('bigint_column').to('integer_column')
end
end
it_behaves_like 'swapping foreign keys correctly'
context 'when foreign key names are 63 bytes' do
let(:foreign_key1) { :f1_012345678901234567890123456789012345678901234567890123456789 }
let(:foreign_key2) { :f2_012345678901234567890123456789012345678901234567890123456789 }
it_behaves_like 'swapping foreign keys correctly'
end
private
def find_foreign_key_by(name)
connection.foreign_keys(table).find { |k| k.options[:name].to_s == name.to_s }
end
end
describe '#swap_indexes' do
let(:table) { :_test_swap_indexes }
let(:index1) { :index_on_integer }
let(:index2) { :index_on_bigint }
before do
connection.execute(<<~SQL)
CREATE TABLE #{table} (
integer_column integer NOT NULL,
bigint_column bigint DEFAULT 0 NOT NULL
);
CREATE INDEX #{index1} ON #{table} USING btree (integer_column);
CREATE INDEX #{index2} ON #{table} USING btree (bigint_column);
SQL
end
shared_examples_for 'swapping indexes correctly' do
specify do
expect { migration_context.swap_indexes(table, index1, index2) }
.to change { find_index_by(index1).columns }.from(['integer_column']).to(['bigint_column'])
.and change { find_index_by(index2).columns }.from(['bigint_column']).to(['integer_column'])
end
end
it_behaves_like 'swapping indexes correctly'
context 'when index names are 63 bytes' do
let(:index1) { :i1_012345678901234567890123456789012345678901234567890123456789 }
let(:index2) { :i2_012345678901234567890123456789012345678901234567890123456789 }
it_behaves_like 'swapping indexes correctly'
end
private
def find_index_by(name)
connection.indexes(table).find { |c| c.name == name.to_s }
end
end
end