Commit 398a0f6d authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Fix constant leaking to subsequent tests

We use an anonymous class so that we don't have to define a new constant
parent bc0228c3
...@@ -3,56 +3,6 @@ ...@@ -3,56 +3,6 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe BulkInsertSafe do RSpec.describe BulkInsertSafe do
class BulkInsertItem < ActiveRecord::Base
include BulkInsertSafe
include ShaAttribute
validates :name, :enum_value, :secret_value, :sha_value, :jsonb_value, presence: true
ENUM_VALUES = {
case_1: 1
}.freeze
sha_attribute :sha_value
enum enum_value: ENUM_VALUES
attr_encrypted :secret_value,
mode: :per_attribute_iv,
algorithm: 'aes-256-gcm',
key: Settings.attr_encrypted_db_key_base_32,
insecure_mode: false
default_value_for :enum_value, 'case_1'
default_value_for :secret_value, 'my-secret'
default_value_for :sha_value, '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12'
default_value_for :jsonb_value, { "key" => "value" }
def self.valid_list(count)
Array.new(count) { |n| new(name: "item-#{n}") }
end
def self.invalid_list(count)
Array.new(count) { new }
end
end
module InheritedUnsafeMethods
extend ActiveSupport::Concern
included do
after_save -> { "unsafe" }
end
end
module InheritedSafeMethods
extend ActiveSupport::Concern
included do
after_initialize -> { "safe" }
end
end
before(:all) do before(:all) do
ActiveRecord::Schema.define do ActiveRecord::Schema.define do
create_table :bulk_insert_items, force: true do |t| create_table :bulk_insert_items, force: true do |t|
...@@ -66,100 +16,155 @@ RSpec.describe BulkInsertSafe do ...@@ -66,100 +16,155 @@ RSpec.describe BulkInsertSafe do
t.index :name, unique: true t.index :name, unique: true
end end
end end
BulkInsertItem.reset_column_information
end end
after(:all) do after(:all) do
ActiveRecord::Schema.define do ActiveRecord::Schema.define do
drop_table :bulk_insert_items, force: true drop_table :bulk_insert_items, force: true
end end
end
let_it_be(:bulk_insert_item_class) do
Class.new(ActiveRecord::Base) do
self.table_name = 'bulk_insert_items'
BulkInsertItem.reset_column_information include BulkInsertSafe
include ShaAttribute
validates :name, :enum_value, :secret_value, :sha_value, :jsonb_value, presence: true
sha_attribute :sha_value
enum enum_value: { case_1: 1 }
attr_encrypted :secret_value,
mode: :per_attribute_iv,
algorithm: 'aes-256-gcm',
key: Settings.attr_encrypted_db_key_base_32,
insecure_mode: false
default_value_for :enum_value, 'case_1'
default_value_for :secret_value, 'my-secret'
default_value_for :sha_value, '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12'
default_value_for :jsonb_value, { "key" => "value" }
def self.name
'BulkInsertItem'
end
def self.valid_list(count)
Array.new(count) { |n| new(name: "item-#{n}") }
end
def self.invalid_list(count)
Array.new(count) { new }
end
end
end end
describe BulkInsertItem do describe 'BulkInsertItem' do
it_behaves_like 'a BulkInsertSafe model', described_class do it_behaves_like 'a BulkInsertSafe model' do
let(:valid_items_for_bulk_insertion) { described_class.valid_list(10) } let(:target_class) { bulk_insert_item_class.dup }
let(:invalid_items_for_bulk_insertion) { described_class.invalid_list(10) } let(:valid_items_for_bulk_insertion) { target_class.valid_list(10) }
let(:invalid_items_for_bulk_insertion) { target_class.invalid_list(10) }
end end
context 'when inheriting class methods' do context 'when inheriting class methods' do
let(:inherited_unsafe_methods_module) do
Module.new do
extend ActiveSupport::Concern
included do
after_save -> { "unsafe" }
end
end
end
let(:inherited_safe_methods_module) do
Module.new do
extend ActiveSupport::Concern
included do
after_initialize -> { "safe" }
end
end
end
it 'raises an error when method is not bulk-insert safe' do it 'raises an error when method is not bulk-insert safe' do
expect { described_class.include(InheritedUnsafeMethods) } expect { bulk_insert_item_class.include(inherited_unsafe_methods_module) }
.to raise_error(described_class::MethodNotAllowedError) .to raise_error(bulk_insert_item_class::MethodNotAllowedError)
end end
it 'does not raise an error when method is bulk-insert safe' do it 'does not raise an error when method is bulk-insert safe' do
expect { described_class.include(InheritedSafeMethods) }.not_to raise_error expect { bulk_insert_item_class.include(inherited_safe_methods_module) }.not_to raise_error
end end
end end
context 'primary keys' do context 'primary keys' do
it 'raises error if primary keys are set prior to insertion' do it 'raises error if primary keys are set prior to insertion' do
item = described_class.new(name: 'valid', id: 10) item = bulk_insert_item_class.new(name: 'valid', id: 10)
expect { described_class.bulk_insert!([item]) } expect { bulk_insert_item_class.bulk_insert!([item]) }
.to raise_error(described_class::PrimaryKeySetError) .to raise_error(bulk_insert_item_class::PrimaryKeySetError)
end end
end end
describe '.bulk_insert!' do describe '.bulk_insert!' do
it 'inserts items in the given number of batches' do it 'inserts items in the given number of batches' do
items = described_class.valid_list(10) items = bulk_insert_item_class.valid_list(10)
expect(ActiveRecord::InsertAll).to receive(:new).twice.and_call_original expect(ActiveRecord::InsertAll).to receive(:new).twice.and_call_original
described_class.bulk_insert!(items, batch_size: 5) bulk_insert_item_class.bulk_insert!(items, batch_size: 5)
end end
it 'items can be properly fetched from database' do it 'items can be properly fetched from database' do
items = described_class.valid_list(10) items = bulk_insert_item_class.valid_list(10)
described_class.bulk_insert!(items) bulk_insert_item_class.bulk_insert!(items)
attribute_names = described_class.attribute_names - %w[id created_at updated_at] attribute_names = bulk_insert_item_class.attribute_names - %w[id created_at updated_at]
expect(described_class.last(items.size).pluck(*attribute_names)).to eq( expect(bulk_insert_item_class.last(items.size).pluck(*attribute_names)).to eq(
items.pluck(*attribute_names)) items.pluck(*attribute_names))
end end
it 'rolls back the transaction when any item is invalid' do it 'rolls back the transaction when any item is invalid' do
# second batch is bad # second batch is bad
all_items = described_class.valid_list(10) + all_items = bulk_insert_item_class.valid_list(10) +
described_class.invalid_list(10) bulk_insert_item_class.invalid_list(10)
expect do expect do
described_class.bulk_insert!(all_items, batch_size: 2) rescue nil bulk_insert_item_class.bulk_insert!(all_items, batch_size: 2) rescue nil
end.not_to change { described_class.count } end.not_to change { bulk_insert_item_class.count }
end end
it 'does nothing and returns an empty array when items are empty' do it 'does nothing and returns an empty array when items are empty' do
expect(described_class.bulk_insert!([])).to eq([]) expect(bulk_insert_item_class.bulk_insert!([])).to eq([])
expect(described_class.count).to eq(0) expect(bulk_insert_item_class.count).to eq(0)
end end
context 'with returns option set' do context 'with returns option set' do
context 'when is set to :ids' do context 'when is set to :ids' do
it 'return an array with the primary key values for all inserted records' do it 'return an array with the primary key values for all inserted records' do
items = described_class.valid_list(1) items = bulk_insert_item_class.valid_list(1)
expect(described_class.bulk_insert!(items, returns: :ids)).to contain_exactly(a_kind_of(Integer)) expect(bulk_insert_item_class.bulk_insert!(items, returns: :ids)).to contain_exactly(a_kind_of(Integer))
end end
end end
context 'when is set to nil' do context 'when is set to nil' do
it 'returns an empty array' do it 'returns an empty array' do
items = described_class.valid_list(1) items = bulk_insert_item_class.valid_list(1)
expect(described_class.bulk_insert!(items, returns: nil)).to eq([]) expect(bulk_insert_item_class.bulk_insert!(items, returns: nil)).to eq([])
end end
end end
context 'when is set to anything else' do context 'when is set to anything else' do
it 'raises an error' do it 'raises an error' do
items = described_class.valid_list(1) items = bulk_insert_item_class.valid_list(1)
expect { described_class.bulk_insert!([items], returns: [:id, :name]) } expect { bulk_insert_item_class.bulk_insert!([items], returns: [:id, :name]) }
.to raise_error(ArgumentError, "returns needs to be :ids or nil") .to raise_error(ArgumentError, "returns needs to be :ids or nil")
end end
end end
...@@ -167,20 +172,20 @@ RSpec.describe BulkInsertSafe do ...@@ -167,20 +172,20 @@ RSpec.describe BulkInsertSafe do
end end
context 'when duplicate items are to be inserted' do context 'when duplicate items are to be inserted' do
let!(:existing_object) { described_class.create!(name: 'duplicate', secret_value: 'old value') } let!(:existing_object) { bulk_insert_item_class.create!(name: 'duplicate', secret_value: 'old value') }
let(:new_object) { described_class.new(name: 'duplicate', secret_value: 'new value') } let(:new_object) { bulk_insert_item_class.new(name: 'duplicate', secret_value: 'new value') }
describe '.bulk_insert!' do describe '.bulk_insert!' do
context 'when skip_duplicates is set to false' do context 'when skip_duplicates is set to false' do
it 'raises an exception' do it 'raises an exception' do
expect { described_class.bulk_insert!([new_object], skip_duplicates: false) } expect { bulk_insert_item_class.bulk_insert!([new_object], skip_duplicates: false) }
.to raise_error(ActiveRecord::RecordNotUnique) .to raise_error(ActiveRecord::RecordNotUnique)
end end
end end
context 'when skip_duplicates is set to true' do context 'when skip_duplicates is set to true' do
it 'does not update existing object' do it 'does not update existing object' do
described_class.bulk_insert!([new_object], skip_duplicates: true) bulk_insert_item_class.bulk_insert!([new_object], skip_duplicates: true)
expect(existing_object.reload.secret_value).to eq('old value') expect(existing_object.reload.secret_value).to eq('old value')
end end
...@@ -189,7 +194,7 @@ RSpec.describe BulkInsertSafe do ...@@ -189,7 +194,7 @@ RSpec.describe BulkInsertSafe do
describe '.bulk_upsert!' do describe '.bulk_upsert!' do
it 'updates existing object' do it 'updates existing object' do
described_class.bulk_upsert!([new_object], unique_by: %w[name]) bulk_insert_item_class.bulk_upsert!([new_object], unique_by: %w[name])
expect(existing_object.reload.secret_value).to eq('new value') expect(existing_object.reload.secret_value).to eq('new value')
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment