mirror of
https://gitlab.com/gitlab-org/gitlab-foss.git
synced 2025-07-25 16:03:48 +00:00
204 lines
4.7 KiB
Ruby
204 lines
4.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'spec_helper'
|
|
|
|
RSpec.describe Gitlab::CircuitBreaker::Store, :clean_gitlab_redis_rate_limiting, feature_category: :ai_abstraction_layer do
|
|
let(:key) { 'key-1' }
|
|
let(:value) { 'value' }
|
|
let(:circuit_store) { described_class.new }
|
|
|
|
shared_examples 'reliable circuit breaker store method' do
|
|
it 'does not raise an error when Redis::BaseConnectionError is encountered' do
|
|
allow(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
|
|
|
|
allow(Gitlab::Redis::RateLimiting)
|
|
.to receive(:with)
|
|
.and_raise(Redis::BaseConnectionError)
|
|
|
|
expect { subject }.not_to raise_error
|
|
end
|
|
end
|
|
|
|
describe '#key?' do
|
|
subject(:key?) { circuit_store.key?(key) }
|
|
|
|
it_behaves_like 'reliable circuit breaker store method'
|
|
|
|
context 'when key exists' do
|
|
before do
|
|
circuit_store.store(key, value)
|
|
end
|
|
|
|
it { is_expected.to eq(true) }
|
|
end
|
|
|
|
context 'when key does not exist' do
|
|
it { is_expected.to eq(false) }
|
|
end
|
|
end
|
|
|
|
describe '#store' do
|
|
let(:options) { {} }
|
|
|
|
subject(:store) { circuit_store.store(key, value, options) }
|
|
|
|
it_behaves_like 'reliable circuit breaker store method'
|
|
|
|
it 'stores value for specified key without expiry by default' do
|
|
expect(store).to eq(value)
|
|
|
|
with_redis do |redis|
|
|
expect(redis.get(key)).to eq(value)
|
|
expect(redis.ttl(key)).to eq(-1)
|
|
end
|
|
end
|
|
|
|
context 'when expires option is set' do
|
|
let(:options) { { expires: 10 } }
|
|
|
|
it 'stores value for specified key with expiry' do
|
|
expect(store).to eq(value)
|
|
|
|
with_redis do |redis|
|
|
expect(redis.get(key)).to eq(value)
|
|
expect(redis.ttl(key)).to eq(10)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#increment' do
|
|
let(:options) { {} }
|
|
|
|
subject(:increment) { circuit_store.increment(key, 1, options) }
|
|
|
|
it_behaves_like 'reliable circuit breaker store method'
|
|
|
|
context 'when key does not exist' do
|
|
it 'sets key and increments value' do
|
|
increment
|
|
|
|
with_redis do |redis|
|
|
expect(redis.get(key).to_i).to eq(1)
|
|
expect(redis.ttl(key)).to eq(-1)
|
|
end
|
|
end
|
|
|
|
context 'with expiry' do
|
|
let(:options) { { expires: 10 } }
|
|
|
|
it 'sets key and increments value with expiration' do
|
|
increment
|
|
|
|
with_redis do |redis|
|
|
expect(redis.get(key).to_i).to eq(1)
|
|
expect(redis.ttl(key)).to eq(10)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when key exists' do
|
|
before do
|
|
circuit_store.store(key, 1)
|
|
end
|
|
|
|
it 'increments value' do
|
|
increment
|
|
|
|
with_redis do |redis|
|
|
expect(redis.get(key).to_i).to eq(2)
|
|
expect(redis.ttl(key)).to eq(-1)
|
|
end
|
|
end
|
|
|
|
context 'with expiry' do
|
|
let(:options) { { expires: 10 } }
|
|
|
|
it 'increments value with expiration' do
|
|
increment
|
|
|
|
with_redis do |redis|
|
|
expect(redis.get(key).to_i).to eq(2)
|
|
expect(redis.ttl(key)).to eq(10)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#load' do
|
|
subject(:load) { circuit_store.load(key) }
|
|
|
|
it_behaves_like 'reliable circuit breaker store method'
|
|
|
|
context 'when key exists' do
|
|
before do
|
|
circuit_store.store(key, value)
|
|
end
|
|
|
|
it 'returns the value of the key' do
|
|
expect(load).to eq(value)
|
|
end
|
|
end
|
|
|
|
context 'when key does not exist' do
|
|
it 'returns nil' do
|
|
expect(load).to be_nil
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#values_at' do
|
|
let(:other_key) { 'key-2' }
|
|
let(:other_value) { 'value-2' }
|
|
|
|
subject(:values_at) { circuit_store.values_at(key, other_key) }
|
|
|
|
it_behaves_like 'reliable circuit breaker store method'
|
|
|
|
context 'when keys exist' do
|
|
before do
|
|
circuit_store.store(key, value)
|
|
circuit_store.store(other_key, other_value)
|
|
end
|
|
|
|
it 'returns values of keys' do
|
|
expect(values_at).to match_array([value, other_value])
|
|
end
|
|
end
|
|
|
|
context 'when some keys do not exist' do
|
|
before do
|
|
circuit_store.store(key, value)
|
|
end
|
|
|
|
it 'returns values of keys with nil for non-existing ones' do
|
|
expect(values_at).to match_array([value, nil])
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#delete' do
|
|
subject(:delete) { circuit_store.delete(key) }
|
|
|
|
before do
|
|
circuit_store.store(key, value)
|
|
end
|
|
|
|
it_behaves_like 'reliable circuit breaker store method'
|
|
|
|
it 'deletes key' do
|
|
delete
|
|
|
|
with_redis do |redis|
|
|
expect(redis.exists?(key)).to eq(false)
|
|
end
|
|
end
|
|
end
|
|
|
|
def with_redis(&block)
|
|
Gitlab::Redis::RateLimiting.with(&block)
|
|
end
|
|
end
|