Commit 6243a93b authored by Mike Kozono's avatar Mike Kozono

Extract ReplicableModel tests against Dummy

instead of writing these tests inside of replicator_spec.rb.
parent 4e9f2bf1
# frozen_string_literal: true
require 'spec_helper'
# Also see ee/spec/support/shared_examples/models/concerns/replicable_model_shared_examples.rb:
#
# - Place tests here in replicable_model_spec.rb if you want to run them once,
# against a DummyModel.
# - Place tests in replicable_model_shared_examples.rb if you want them to be
# run against every real Model.
RSpec.describe Gitlab::Geo::ReplicableModel do
include ::EE::GeoHelpers
let_it_be(:primary_node) { create(:geo_node, :primary) }
let_it_be(:secondary_node) { create(:geo_node) }
before(:all) do
create_dummy_model_table
end
after(:all) do
drop_dummy_model_table
end
before do
stub_dummy_replicator_class
stub_dummy_model_class
end
subject { DummyModel.new }
it_behaves_like 'a replicable model' do
let(:model_record) { subject }
end
describe '#replicator' do
it 'adds replicator method to the model' do
expect(subject).to respond_to(:replicator)
end
it 'instantiates a replicator into the model' do
expect(subject.replicator).to be_a(Geo::DummyReplicator)
end
end
end
...@@ -21,221 +21,169 @@ RSpec.describe Gitlab::Geo::Replicator do ...@@ -21,221 +21,169 @@ RSpec.describe Gitlab::Geo::Replicator do
end end
before(:all) do before(:all) do
ActiveRecord::Schema.define do create_dummy_model_table
create_table :dummy_models, force: true do |t|
t.binary :verification_checksum
end
end
end end
after(:all) do after(:all) do
ActiveRecord::Schema.define do drop_dummy_model_table
drop_table :dummy_models, force: true
end
end end
context 'with defined events' do before do
before do stub_dummy_replicator_class
stub_const('Geo::DummyReplicator', Class.new(Gitlab::Geo::Replicator)) end
Geo::DummyReplicator.class_eval do
event :test
event :another_test
def self.model
::DummyModel
end
protected context 'event DSL' do
subject { Geo::DummyReplicator }
def consume_event_test(user:, other:) describe '.supported_events' do
true it 'expects :test event to be supported' do
end expect(subject.supported_events).to match_array([:test, :another_test])
end end
end end
context 'event DSL' do describe '.event_supported?' do
subject { Geo::DummyReplicator } it 'expects a supported event to return true' do
expect(subject.event_supported?(:test)).to be_truthy
describe '.supported_events' do
it 'expects :test event to be supported' do
expect(subject.supported_events).to match_array([:test, :another_test])
end
end end
describe '.event_supported?' do it 'expect an unsupported event to return false' do
it 'expects a supported event to return true' do expect(subject.event_supported?(:something_else)).to be_falsey
expect(subject.event_supported?(:test)).to be_truthy
end
it 'expect an unsupported event to return false' do
expect(subject.event_supported?(:something_else)).to be_falsey
end
end end
end end
end
context 'model DSL' do describe '#publish' do
before do subject { Geo::DummyReplicator.new }
stub_const('DummyModel', Class.new(ApplicationRecord))
DummyModel.class_eval do
include ActiveModel::Model
def self.after_create_commit(*args)
end
include Gitlab::Geo::ReplicableModel
with_replicator Geo::DummyReplicator
end
DummyModel.reset_column_information
end
subject { DummyModel.new } context 'when publishing a supported events with required params' do
it 'creates event with associated event log record' do
stub_current_geo_node(primary_node)
it 'adds replicator method to the model' do expect { subject.publish(:test, other: true) }.to change { ::Geo::EventLog.count }.from(0).to(1)
expect(subject).to respond_to(:replicator)
end
it 'instantiates a replicator into the model' do expect(::Geo::EventLog.last.event).to be_a(::Geo::Event)
expect(subject.replicator).to be_a(Geo::DummyReplicator)
end end
end end
describe '#publish' do context 'when publishing unsupported event' do
subject { Geo::DummyReplicator.new } it 'raises an argument error' do
expect { subject.publish(:unsupported) }.to raise_error(ArgumentError)
context 'when publishing a supported events with required params' do
it 'creates event with associated event log record' do
stub_current_geo_node(primary_node)
expect { subject.publish(:test, other: true) }.to change { ::Geo::EventLog.count }.from(0).to(1)
expect(::Geo::EventLog.last.event).to be_a(::Geo::Event)
end
end
context 'when publishing unsupported event' do
it 'raises an argument error' do
expect { subject.publish(:unsupported) }.to raise_error(ArgumentError)
end
end end
end end
end
describe '#consume' do describe '#consume' do
subject { Geo::DummyReplicator.new } subject { Geo::DummyReplicator.new }
it 'accepts valid attributes' do it 'accepts valid attributes' do
expect { subject.consume(:test, user: 'something', other: 'something else') }.not_to raise_error expect { subject.consume(:test, user: 'something', other: 'something else') }.not_to raise_error
end end
it 'calls corresponding method with specified named attributes' do it 'calls corresponding method with specified named attributes' do
expect(subject).to receive(:consume_event_test).with(user: 'something', other: 'something else') expect(subject).to receive(:consume_event_test).with(user: 'something', other: 'something else')
subject.consume(:test, user: 'something', other: 'something else') subject.consume(:test, user: 'something', other: 'something else')
end
end end
end
describe '.for_class_name' do describe '.for_class_name' do
context 'when given a Geo RegistryFinder' do context 'when given a Geo RegistryFinder' do
it 'returns the corresponding Replicator class' do it 'returns the corresponding Replicator class' do
expect(described_class.for_class_name('Geo::DummyRegistryFinder')).to eq(Geo::DummyReplicator) expect(described_class.for_class_name('Geo::DummyRegistryFinder')).to eq(Geo::DummyReplicator)
end
end end
end
context 'when given a Geo RegistriesResolver"' do context 'when given a Geo RegistriesResolver"' do
it 'returns the corresponding Replicator class' do it 'returns the corresponding Replicator class' do
expect(described_class.for_class_name('Geo::DummyRegistriesResolver')).to eq(Geo::DummyReplicator) expect(described_class.for_class_name('Geo::DummyRegistriesResolver')).to eq(Geo::DummyReplicator)
end
end end
end end
end
describe '.for_replicable_name' do describe '.for_replicable_name' do
context 'given a valid replicable_name' do context 'given a valid replicable_name' do
it 'returns the corresponding Replicator class' do it 'returns the corresponding Replicator class' do
replicator_class = described_class.for_replicable_name('dummy') replicator_class = described_class.for_replicable_name('dummy')
expect(replicator_class).to eq(Geo::DummyReplicator) expect(replicator_class).to eq(Geo::DummyReplicator)
end
end end
end
context 'given an invalid replicable_name' do context 'given an invalid replicable_name' do
it 'raises and logs NotImplementedError' do it 'raises and logs NotImplementedError' do
expect(Gitlab::Geo::Logger).to receive(:error) expect(Gitlab::Geo::Logger).to receive(:error)
expect do expect do
described_class.for_replicable_name('invalid') described_class.for_replicable_name('invalid')
end.to raise_error(NotImplementedError) end.to raise_error(NotImplementedError)
end
end end
end
context 'given nil' do context 'given nil' do
it 'raises NotImplementedError' do it 'raises NotImplementedError' do
expect do expect do
described_class.for_replicable_name('invalid') described_class.for_replicable_name('invalid')
end.to raise_error(NotImplementedError) end.to raise_error(NotImplementedError)
end
end end
end end
end
describe '.for_replicable_params' do describe '.for_replicable_params' do
it 'returns the corresponding Replicator instance' do it 'returns the corresponding Replicator instance' do
replicator = described_class.for_replicable_params(replicable_name: 'dummy', replicable_id: 123456) replicator = described_class.for_replicable_params(replicable_name: 'dummy', replicable_id: 123456)
expect(replicator).to be_a(Geo::DummyReplicator) expect(replicator).to be_a(Geo::DummyReplicator)
expect(replicator.model_record_id).to eq(123456) expect(replicator.model_record_id).to eq(123456)
end
end end
end
describe '.replicable_params' do describe '.replicable_params' do
it 'returns a Hash of data needed to reinstantiate the Replicator' do it 'returns a Hash of data needed to reinstantiate the Replicator' do
replicator = Geo::DummyReplicator.new(model_record_id: 123456) replicator = Geo::DummyReplicator.new(model_record_id: 123456)
expect(replicator.replicable_params).to eq(replicable_name: 'dummy', replicable_id: 123456) expect(replicator.replicable_params).to eq(replicable_name: 'dummy', replicable_id: 123456)
end
end end
end
describe '#initialize' do describe '#initialize' do
subject(:replicator) { Geo::DummyReplicator.new(**args) } subject(:replicator) { Geo::DummyReplicator.new(**args) }
let(:model_record) { double('DummyModel instance', id: 1234) } let(:model_record) { double('DummyModel instance', id: 1234) }
context 'given model_record' do context 'given model_record' do
let(:args) { { model_record: model_record } } let(:args) { { model_record: model_record } }
it 'sets model_record' do it 'sets model_record' do
expect(replicator.model_record).to eq(model_record) expect(replicator.model_record).to eq(model_record)
end end
it 'sets model_record_id' do it 'sets model_record_id' do
expect(replicator.model_record_id).to eq(1234) expect(replicator.model_record_id).to eq(1234)
end
end end
end
context 'given model_record_id' do context 'given model_record_id' do
let(:args) { { model_record_id: 1234 } } let(:args) { { model_record_id: 1234 } }
before do before do
model = double('DummyModel') model = double('DummyModel')
# These two stubs are needed because `#model_record` instantiates the # These two stubs are needed because `#model_record` instantiates the
# defined `.model` class. # defined `.model` class.
allow(Geo::DummyReplicator).to receive(:model).and_return(model) allow(Geo::DummyReplicator).to receive(:model).and_return(model)
allow(model).to receive(:find).with(1234).and_return(model_record) allow(model).to receive(:find).with(1234).and_return(model_record)
end end
it 'sets model_record' do it 'sets model_record' do
expect(replicator.model_record).to eq(model_record) expect(replicator.model_record).to eq(model_record)
end end
it 'sets model_record_id' do it 'sets model_record_id' do
expect(replicator.model_record_id).to eq(1234) expect(replicator.model_record_id).to eq(1234)
end
end end
end end
end
describe '#in_replicables_for_geo_node?' do describe '#in_replicables_for_geo_node?' do
it { is_expected.to delegate_method(:in_replicables_for_geo_node?).to(:model_record) } it { is_expected.to delegate_method(:in_replicables_for_geo_node?).to(:model_record) }
end
end end
end end
...@@ -55,5 +55,67 @@ module EE ...@@ -55,5 +55,67 @@ module EE
# will appear as though the tracking DB were not available # will appear as though the tracking DB were not available
allow(::Gitlab::Geo).to receive(:geo_database_configured?).and_call_original allow(::Gitlab::Geo).to receive(:geo_database_configured?).and_call_original
end end
def stub_dummy_replicator_class
stub_const('Geo::DummyReplicator', Class.new(::Gitlab::Geo::Replicator))
Geo::DummyReplicator.class_eval do
event :test
event :another_test
def self.model
::DummyModel
end
def handle_after_create_commit
true
end
protected
def consume_event_test(user:, other:)
true
end
end
end
def stub_dummy_model_class
stub_const('DummyModel', Class.new(ApplicationRecord))
DummyModel.class_eval do
include ::Gitlab::Geo::ReplicableModel
with_replicator Geo::DummyReplicator
def self.replicables_for_geo_node
self.all
end
end
DummyModel.reset_column_information
end
# Example:
#
# before(:all) do
# create_dummy_model_table
# end
#
# after(:all) do
# drop_dummy_model_table
# end
def create_dummy_model_table
ActiveRecord::Schema.define do
create_table :dummy_models, force: true do |t|
t.binary :verification_checksum
end
end
end
def drop_dummy_model_table
ActiveRecord::Schema.define do
drop_table :dummy_models, force: true
end
end
end end
end end
...@@ -6,6 +6,13 @@ ...@@ -6,6 +6,13 @@
# #
# We do not use `described_class` here, so we can include this in replicator # We do not use `described_class` here, so we can include this in replicator
# strategy shared examples instead of in *every* model spec. # strategy shared examples instead of in *every* model spec.
#
# Also see ee/spec/lib/gitlab/geo/replicable_model_spec.rb:
#
# - Place tests in replicable_model_spec.rb if you want to run them once,
# against a DummyModel.
# - Place tests here in replicable_model_shared_examples.rb if you want them to
# be run against every real Model.
RSpec.shared_examples 'a replicable model' do RSpec.shared_examples 'a replicable model' do
include EE::GeoHelpers include EE::GeoHelpers
......
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