diff options
Diffstat (limited to 'spec/models/concerns/safely_change_column_default_spec.rb')
-rw-r--r-- | spec/models/concerns/safely_change_column_default_spec.rb | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/spec/models/concerns/safely_change_column_default_spec.rb b/spec/models/concerns/safely_change_column_default_spec.rb new file mode 100644 index 00000000000..36782170eaf --- /dev/null +++ b/spec/models/concerns/safely_change_column_default_spec.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe SafelyChangeColumnDefault, feature_category: :database do + include Gitlab::Database::DynamicModelHelpers + before do + ApplicationRecord.connection.execute(<<~SQL) + CREATE TABLE _test_gitlab_main_data( + id bigserial primary key not null, + value bigint default 1 + ); + SQL + end + + let!(:model) do + define_batchable_model('_test_gitlab_main_data', connection: ApplicationRecord.connection).tap do |model| + model.include(described_class) + model.columns_changing_default(:value) + model.columns # Force the schema cache to populate + end + end + + def alter_default(new_default) + ApplicationRecord.connection.execute(<<~SQL) + ALTER TABLE _test_gitlab_main_data ALTER COLUMN value SET DEFAULT #{new_default} + SQL + end + + def recorded_insert_queries(&block) + recorder = ActiveRecord::QueryRecorder.new + recorder.record(&block) + + recorder.log.select { |q| q.include?('INSERT INTO') } + end + + def query_includes_value_column?(query) + parsed = PgQuery.parse(query) + parsed.tree.stmts.first.stmt.insert_stmt.cols.any? { |node| node.res_target.name == 'value' } + end + + it 'forces the column to be written on a change' do + queries = recorded_insert_queries do + model.create!(value: 1) + end + + expect(queries.length).to eq(1) + + expect(query_includes_value_column?(queries.first)).to be_truthy + end + + it 'does not write the column without a change' do + queries = recorded_insert_queries do + model.create! + end + + expect(queries.length).to eq(1) + expect(query_includes_value_column?(queries.first)).to be_falsey + end + + it 'does not send the old column value if the default has changed' do + alter_default(2) + model.create! + + expect(model.pluck(:value)).to contain_exactly(2) + end + + it 'prevents writing new default in place of the old default' do + alter_default(2) + + model.create!(value: 1) + + expect(model.pluck(:value)).to contain_exactly(1) + end +end |