Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/redis/multi_store_spec.rb')
-rw-r--r--spec/lib/gitlab/redis/multi_store_spec.rb544
1 files changed, 175 insertions, 369 deletions
diff --git a/spec/lib/gitlab/redis/multi_store_spec.rb b/spec/lib/gitlab/redis/multi_store_spec.rb
index 8b73b5e03c0..207fe28e84e 100644
--- a/spec/lib/gitlab/redis/multi_store_spec.rb
+++ b/spec/lib/gitlab/redis/multi_store_spec.rb
@@ -127,19 +127,15 @@ RSpec.describe Gitlab::Redis::MultiStore do
end
before(:all) do
- primary_store.multi do |multi|
- multi.set(key1, value1)
- multi.set(key2, value2)
- multi.sadd(skey, value1)
- multi.sadd(skey, value2)
- end
+ primary_store.set(key1, value1)
+ primary_store.set(key2, value2)
+ primary_store.sadd?(skey, value1)
+ primary_store.sadd?(skey, value2)
- secondary_store.multi do |multi|
- multi.set(key1, value1)
- multi.set(key2, value2)
- multi.sadd(skey, value1)
- multi.sadd(skey, value2)
- end
+ secondary_store.set(key1, value1)
+ secondary_store.set(key2, value2)
+ secondary_store.sadd?(skey, value1)
+ secondary_store.sadd?(skey, value2)
end
RSpec.shared_examples_for 'reads correct value' do
@@ -211,126 +207,86 @@ RSpec.describe Gitlab::Redis::MultiStore do
end
with_them do
- describe "#{name}" do
+ describe name.to_s do
before do
allow(primary_store).to receive(name).and_call_original
allow(secondary_store).to receive(name).and_call_original
end
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: true)
- end
-
- context 'when reading from the primary is successful' do
- it 'returns the correct value' do
- expect(primary_store).to receive(name).with(*args).and_call_original
-
- subject
- end
-
- it 'does not execute on the secondary store' do
- expect(secondary_store).not_to receive(name)
+ context 'when reading from the primary is successful' do
+ it 'returns the correct value' do
+ expect(primary_store).to receive(name).with(*args).and_call_original
- subject
- end
-
- include_examples 'reads correct value'
+ subject
end
- context 'when reading from primary instance is raising an exception' do
- before do
- allow(primary_store).to receive(name).with(*args).and_raise(StandardError)
- allow(Gitlab::ErrorTracking).to receive(:log_exception)
- end
+ it 'does not execute on the secondary store' do
+ expect(secondary_store).not_to receive(name)
- it 'logs the exception' do
- expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
- hash_including(:multi_store_error_message, instance_name: instance_name, command_name: name))
+ subject
+ end
- subject
- end
+ include_examples 'reads correct value'
+ end
- include_examples 'fallback read from the secondary store'
+ context 'when reading from primary instance is raising an exception' do
+ before do
+ allow(primary_store).to receive(name).with(*args).and_raise(StandardError)
+ allow(Gitlab::ErrorTracking).to receive(:log_exception)
end
- context 'when reading from primary instance return no value' do
- before do
- allow(primary_store).to receive(name).and_return(nil)
- end
+ it 'logs the exception' do
+ expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
+ hash_including(:multi_store_error_message, instance_name: instance_name, command_name: name))
- include_examples 'fallback read from the secondary store'
+ subject
end
- context 'when the command is executed within pipelined block' do
- subject do
- multi_store.pipelined do |pipeline|
- pipeline.send(name, *args)
- end
- end
+ include_examples 'fallback read from the secondary store'
+ end
- it 'is executed only 1 time on primary and secondary instance' do
- expect(primary_store).to receive(:pipelined).and_call_original
- expect(secondary_store).to receive(:pipelined).and_call_original
+ context 'when reading from primary instance return no value' do
+ before do
+ allow(primary_store).to receive(name).and_return(nil)
+ end
- 2.times do
- expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
- expect(pipeline).to receive(name).with(*args).once.and_call_original
- end
- end
+ include_examples 'fallback read from the secondary store'
+ end
- subject
+ context 'when the command is executed within pipelined block' do
+ subject do
+ multi_store.pipelined do |pipeline|
+ pipeline.send(name, *args)
end
end
- if params[:block]
- subject do
- multi_store.send(name, *args, &block)
- end
-
- context 'when block is provided' do
- it 'yields to the block' do
- expect(primary_store).to receive(name).and_yield(value)
+ it 'is executed only 1 time on primary and secondary instance' do
+ expect(primary_store).to receive(:pipelined).and_call_original
+ expect(secondary_store).to receive(:pipelined).and_call_original
- subject
+ 2.times do
+ expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
+ expect(pipeline).to receive(name).with(*args).once.and_call_original
end
-
- include_examples 'reads correct value'
end
- end
- end
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: false)
+ subject
end
+ end
- context 'with feature flag :use_primary_store_as_default_for_test_store is disabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: false)
- end
-
- it_behaves_like 'secondary store'
+ if params[:block]
+ subject do
+ multi_store.send(name, *args, &block)
end
- context 'with feature flag :use_primary_store_as_default_for_test_store is enabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: true)
- end
-
- it 'execute on the primary instance' do
- expect(primary_store).to receive(name).with(*args).and_call_original
+ context 'when block is provided' do
+ it 'yields to the block' do
+ expect(primary_store).to receive(name).and_yield(value)
subject
end
include_examples 'reads correct value'
-
- it 'does not execute on the secondary store' do
- expect(secondary_store).not_to receive(name)
-
- subject
- end
end
end
@@ -372,8 +328,9 @@ RSpec.describe Gitlab::Redis::MultiStore do
let_it_be(:skey) { "redis:set:key" }
let_it_be(:svalues1) { [value2, value1] }
let_it_be(:svalues2) { [value1] }
- let_it_be(:skey_value1) { [skey, value1] }
- let_it_be(:skey_value2) { [skey, value2] }
+ let_it_be(:skey_value1) { [skey, [value1]] }
+ let_it_be(:skey_value2) { [skey, [value2]] }
+ let_it_be(:script) { %(redis.call("set", "#{key1}", "#{value1}")) }
where(:case_name, :name, :args, :expected_value, :verification_name, :verification_args) do
'execute :set command' | :set | ref(:key1_value1) | ref(:value1) | :get | ref(:key1)
@@ -383,25 +340,22 @@ RSpec.describe Gitlab::Redis::MultiStore do
'execute :srem command' | :srem | ref(:skey_value1) | [] | :smembers | ref(:skey)
'execute :del command' | :del | ref(:key2) | nil | :get | ref(:key2)
'execute :flushdb command' | :flushdb | nil | 0 | :dbsize | nil
+ 'execute :eval command' | :eval | ref(:script) | ref(:value1) | :get | ref(:key1)
end
before do
primary_store.flushdb
secondary_store.flushdb
- primary_store.multi do |multi|
- multi.set(key2, value1)
- multi.sadd(skey, value1)
- end
+ primary_store.set(key2, value1)
+ primary_store.sadd?(skey, value1)
- secondary_store.multi do |multi|
- multi.set(key2, value1)
- multi.sadd(skey, value1)
- end
+ secondary_store.set(key2, value1)
+ secondary_store.sadd?(skey, value1)
end
with_them do
- describe "#{name}" do
+ describe name.to_s do
let(:expected_args) { args || no_args }
before do
@@ -409,100 +363,58 @@ RSpec.describe Gitlab::Redis::MultiStore do
allow(secondary_store).to receive(name).and_call_original
end
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: true)
- end
-
- context 'when executing on primary instance is successful' do
- it 'executes on both primary and secondary redis store', :aggregate_errors do
- expect(primary_store).to receive(name).with(*expected_args).and_call_original
- expect(secondary_store).to receive(name).with(*expected_args).and_call_original
-
- subject
- end
-
- include_examples 'verify that store contains values', :primary_store
- include_examples 'verify that store contains values', :secondary_store
- end
-
- context 'when executing on the primary instance is raising an exception' do
- before do
- allow(primary_store).to receive(name).with(*expected_args).and_raise(StandardError)
- allow(Gitlab::ErrorTracking).to receive(:log_exception)
- end
-
- it 'logs the exception and execute on secondary instance', :aggregate_errors do
- expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
- hash_including(:multi_store_error_message, command_name: name, instance_name: instance_name))
- expect(secondary_store).to receive(name).with(*expected_args).and_call_original
-
- subject
- end
+ context 'when executing on primary instance is successful' do
+ it 'executes on both primary and secondary redis store', :aggregate_errors do
+ expect(primary_store).to receive(name).with(*expected_args).and_call_original
+ expect(secondary_store).to receive(name).with(*expected_args).and_call_original
- include_examples 'verify that store contains values', :secondary_store
+ subject
end
- context 'when the command is executed within pipelined block' do
- subject do
- multi_store.pipelined do |pipeline|
- pipeline.send(name, *args)
- end
- end
-
- it 'is executed only 1 time on each instance', :aggregate_errors do
- expect(primary_store).to receive(:pipelined).and_call_original
- expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
- expect(pipeline).to receive(name).with(*expected_args).once.and_call_original
- end
-
- expect(secondary_store).to receive(:pipelined).and_call_original
- expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
- expect(pipeline).to receive(name).with(*expected_args).once.and_call_original
- end
-
- subject
- end
-
- include_examples 'verify that store contains values', :primary_store
- include_examples 'verify that store contains values', :secondary_store
- end
+ include_examples 'verify that store contains values', :primary_store
+ include_examples 'verify that store contains values', :secondary_store
end
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store is disabled' do
+ context 'when executing on the primary instance is raising an exception' do
before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: false)
+ allow(primary_store).to receive(name).with(*expected_args).and_raise(StandardError)
+ allow(Gitlab::ErrorTracking).to receive(:log_exception)
end
- context 'with feature flag :use_primary_store_as_default_for_test_store is disabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: false)
- end
+ it 'logs the exception and execute on secondary instance', :aggregate_errors do
+ expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
+ hash_including(:multi_store_error_message, command_name: name, instance_name: instance_name))
+ expect(secondary_store).to receive(name).with(*expected_args).and_call_original
+
+ subject
+ end
- it 'executes only on the secondary redis store', :aggregate_errors do
- expect(secondary_store).to receive(name).with(*expected_args)
- expect(primary_store).not_to receive(name).with(*expected_args)
+ include_examples 'verify that store contains values', :secondary_store
+ end
- subject
+ context 'when the command is executed within pipelined block' do
+ subject do
+ multi_store.pipelined do |pipeline|
+ pipeline.send(name, *args)
end
-
- include_examples 'verify that store contains values', :secondary_store
end
- context 'with feature flag :use_primary_store_as_default_for_test_store is enabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: true)
+ it 'is executed only 1 time on each instance', :aggregate_errors do
+ expect(primary_store).to receive(:pipelined).and_call_original
+ expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
+ expect(pipeline).to receive(name).with(*expected_args).once.and_call_original
end
- it 'executes only on the primary_redis redis store', :aggregate_errors do
- expect(primary_store).to receive(name).with(*expected_args)
- expect(secondary_store).not_to receive(name).with(*expected_args)
-
- subject
+ expect(secondary_store).to receive(:pipelined).and_call_original
+ expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
+ expect(pipeline).to receive(name).with(*expected_args).once.and_call_original
end
- include_examples 'verify that store contains values', :primary_store
+ subject
end
+
+ include_examples 'verify that store contains values', :primary_store
+ include_examples 'verify that store contains values', :secondary_store
end
end
end
@@ -537,151 +449,109 @@ RSpec.describe Gitlab::Redis::MultiStore do
end
end
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: true)
- end
-
- context 'when executing on primary instance is successful' do
- it 'executes on both primary and secondary redis store', :aggregate_errors do
- expect(primary_store).to receive(name).and_call_original
- expect(secondary_store).to receive(name).and_call_original
-
- subject
- end
+ context 'when executing on primary instance is successful' do
+ it 'executes on both primary and secondary redis store', :aggregate_errors do
+ expect(primary_store).to receive(name).and_call_original
+ expect(secondary_store).to receive(name).and_call_original
- include_examples 'verify that store contains values', :primary_store
- include_examples 'verify that store contains values', :secondary_store
+ subject
end
- context 'when executing on the primary instance is raising an exception' do
- before do
- allow(primary_store).to receive(name).and_raise(StandardError)
- allow(Gitlab::ErrorTracking).to receive(:log_exception)
- end
-
- it 'logs the exception and execute on secondary instance', :aggregate_errors do
- expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
- hash_including(:multi_store_error_message, command_name: name))
- expect(secondary_store).to receive(name).and_call_original
-
- subject
- end
+ include_examples 'verify that store contains values', :primary_store
+ include_examples 'verify that store contains values', :secondary_store
+ end
- include_examples 'verify that store contains values', :secondary_store
+ context 'when executing on the primary instance is raising an exception' do
+ before do
+ allow(primary_store).to receive(name).and_raise(StandardError)
+ allow(Gitlab::ErrorTracking).to receive(:log_exception)
end
- describe 'return values from a pipelined command' do
- RSpec::Matchers.define :pipeline_diff_error_with_stacktrace do |message|
- match do |object|
- expect(object).to be_a(Gitlab::Redis::MultiStore::PipelinedDiffError)
- expect(object.backtrace).not_to be_nil
- expect(object.message).to eq(message)
- end
- end
+ it 'logs the exception and execute on secondary instance', :aggregate_errors do
+ expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
+ hash_including(:multi_store_error_message, command_name: name))
+ expect(secondary_store).to receive(name).and_call_original
- subject do
- multi_store.send(name) do |redis|
- redis.get(key1)
- end
- end
-
- context 'when the value exists on both and are equal' do
- before do
- primary_store.set(key1, value1)
- secondary_store.set(key1, value1)
- end
+ subject
+ end
- it 'returns the value' do
- expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
+ include_examples 'verify that store contains values', :secondary_store
+ end
- expect(subject).to eq([value1])
- end
+ describe 'return values from a pipelined command' do
+ RSpec::Matchers.define :pipeline_diff_error_with_stacktrace do |message|
+ match do |object|
+ expect(object).to be_a(Gitlab::Redis::MultiStore::PipelinedDiffError)
+ expect(object.backtrace).not_to be_nil
+ expect(object.message).to eq(message)
end
+ end
- context 'when the value exists on both but differ' do
- before do
- primary_store.set(key1, value1)
- secondary_store.set(key1, value2)
- end
-
- it 'returns the value from the secondary store, logging an error' do
- expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
- pipeline_diff_error_with_stacktrace(
- 'Pipelined command executed on both stores successfully but results differ between them. ' \
- "Result from the primary: [#{value1.inspect}]. Result from the secondary: [#{value2.inspect}]."
- ),
- hash_including(command_name: name, instance_name: instance_name)
- ).and_call_original
- expect(counter).to receive(:increment).with(command: name, instance_name: instance_name)
-
- expect(subject).to eq([value2])
- end
+ subject do
+ multi_store.send(name) do |redis|
+ redis.get(key1)
end
+ end
- context 'when the value does not exist on the primary but it does on the secondary' do
- before do
- secondary_store.set(key1, value2)
- end
-
- it 'returns the value from the secondary store, logging an error' do
- expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
- pipeline_diff_error_with_stacktrace(
- 'Pipelined command executed on both stores successfully but results differ between them. ' \
- "Result from the primary: [nil]. Result from the secondary: [#{value2.inspect}]."
- ),
- hash_including(command_name: name, instance_name: instance_name)
- )
- expect(counter).to receive(:increment).with(command: name, instance_name: instance_name)
-
- expect(subject).to eq([value2])
- end
+ context 'when the value exists on both and are equal' do
+ before do
+ primary_store.set(key1, value1)
+ secondary_store.set(key1, value1)
end
- context 'when the value does not exist in either' do
- it 'returns nil without logging an error' do
- expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
- expect(counter).not_to receive(:increment)
+ it 'returns the value' do
+ expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
- expect(subject).to eq([nil])
- end
+ expect(subject).to eq([value1])
end
end
- end
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store is disabled' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: false)
- end
-
- context 'with feature flag :use_primary_store_as_default_for_test_store is disabled' do
+ context 'when the value exists on both but differ' do
before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: false)
+ primary_store.set(key1, value1)
+ secondary_store.set(key1, value2)
end
- it 'executes only on the secondary redis store', :aggregate_errors do
- expect(secondary_store).to receive(name)
- expect(primary_store).not_to receive(name)
-
- subject
+ it 'returns the value from the secondary store, logging an error' do
+ expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
+ pipeline_diff_error_with_stacktrace(
+ 'Pipelined command executed on both stores successfully but results differ between them. ' \
+ "Result from the primary: [#{value1.inspect}]. Result from the secondary: [#{value2.inspect}]."
+ ),
+ hash_including(command_name: name, instance_name: instance_name)
+ ).and_call_original
+ expect(counter).to receive(:increment).with(command: name, instance_name: instance_name)
+
+ expect(subject).to eq([value2])
end
-
- include_examples 'verify that store contains values', :secondary_store
end
- context 'with feature flag :use_primary_store_as_default_for_test_store is enabled' do
+ context 'when the value does not exist on the primary but it does on the secondary' do
before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: true)
+ secondary_store.set(key1, value2)
end
- it 'executes only on the primary_redis redis store', :aggregate_errors do
- expect(primary_store).to receive(name)
- expect(secondary_store).not_to receive(name)
-
- subject
+ it 'returns the value from the secondary store, logging an error' do
+ expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
+ pipeline_diff_error_with_stacktrace(
+ 'Pipelined command executed on both stores successfully but results differ between them. ' \
+ "Result from the primary: [nil]. Result from the secondary: [#{value2.inspect}]."
+ ),
+ hash_including(command_name: name, instance_name: instance_name)
+ )
+ expect(counter).to receive(:increment).with(command: name, instance_name: instance_name)
+
+ expect(subject).to eq([value2])
end
+ end
- include_examples 'verify that store contains values', :primary_store
+ context 'when the value does not exist in either' do
+ it 'returns nil without logging an error' do
+ expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
+ expect(counter).not_to receive(:increment)
+
+ expect(subject).to eq([nil])
+ end
end
end
end
@@ -825,40 +695,8 @@ RSpec.describe Gitlab::Redis::MultiStore do
describe '#to_s' do
subject { multi_store.to_s }
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store is enabled' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: true)
- end
-
- it 'returns same value as primary_store' do
- is_expected.to eq(primary_store.to_s)
- end
- end
-
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store is disabled' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: false)
- end
-
- context 'with feature flag :use_primary_store_as_default_for_test_store is enabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: true)
- end
-
- it 'returns same value as primary_store' do
- is_expected.to eq(primary_store.to_s)
- end
- end
-
- context 'with feature flag :use_primary_store_as_default_for_test_store is disabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: false)
- end
-
- it 'returns same value as primary_store' do
- is_expected.to eq(secondary_store.to_s)
- end
- end
+ it 'returns same value as primary_store' do
+ is_expected.to eq(primary_store.to_s)
end
end
@@ -869,24 +707,8 @@ RSpec.describe Gitlab::Redis::MultiStore do
end
describe '#use_primary_and_secondary_stores?' do
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store is enabled' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: true)
- end
-
- it 'multi store is disabled' do
- expect(multi_store.use_primary_and_secondary_stores?).to be true
- end
- end
-
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store is disabled' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: false)
- end
-
- it 'multi store is disabled' do
- expect(multi_store.use_primary_and_secondary_stores?).to be false
- end
+ it 'multi store is enabled' do
+ expect(multi_store.use_primary_and_secondary_stores?).to be true
end
context 'with empty DB' do
@@ -911,24 +733,8 @@ RSpec.describe Gitlab::Redis::MultiStore do
end
describe '#use_primary_store_as_default?' do
- context 'with feature flag :use_primary_store_as_default_for_test_store is enabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: true)
- end
-
- it 'multi store is disabled' do
- expect(multi_store.use_primary_store_as_default?).to be true
- end
- end
-
- context 'with feature flag :use_primary_store_as_default_for_test_store is disabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: false)
- end
-
- it 'multi store is disabled' do
- expect(multi_store.use_primary_store_as_default?).to be false
- end
+ it 'multi store is disabled' do
+ expect(multi_store.use_primary_store_as_default?).to be true
end
context 'with empty DB' do