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:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-08-18 13:50:51 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-08-18 13:50:51 +0300
commitdb384e6b19af03b4c3c82a5760d83a3fd79f7982 (patch)
tree34beaef37df5f47ccbcf5729d7583aae093cffa0 /gems/gitlab-safe_request_store
parent54fd7b1bad233e3944434da91d257fa7f63c3996 (diff)
Add latest changes from gitlab-org/gitlab@16-3-stable-eev16.3.0-rc42
Diffstat (limited to 'gems/gitlab-safe_request_store')
-rw-r--r--gems/gitlab-safe_request_store/.gitignore11
-rw-r--r--gems/gitlab-safe_request_store/.gitlab-ci.yml4
-rw-r--r--gems/gitlab-safe_request_store/.rspec3
-rw-r--r--gems/gitlab-safe_request_store/.rubocop.yml2
-rw-r--r--gems/gitlab-safe_request_store/Gemfile6
-rw-r--r--gems/gitlab-safe_request_store/Gemfile.lock103
-rw-r--r--gems/gitlab-safe_request_store/README.md42
-rw-r--r--gems/gitlab-safe_request_store/gitlab-safe_request_store.gemspec28
-rw-r--r--gems/gitlab-safe_request_store/lib/gitlab/safe_request_store.rb73
-rw-r--r--gems/gitlab-safe_request_store/lib/gitlab/safe_request_store/null_store.rb45
-rw-r--r--gems/gitlab-safe_request_store/lib/gitlab/safe_request_store/version.rb9
-rw-r--r--gems/gitlab-safe_request_store/spec/gitlab/safe_request_store/null_store_spec.rb75
-rw-r--r--gems/gitlab-safe_request_store/spec/gitlab/safe_request_store_spec.rb281
-rw-r--r--gems/gitlab-safe_request_store/spec/spec_helper.rb19
14 files changed, 701 insertions, 0 deletions
diff --git a/gems/gitlab-safe_request_store/.gitignore b/gems/gitlab-safe_request_store/.gitignore
new file mode 100644
index 00000000000..b04a8c840df
--- /dev/null
+++ b/gems/gitlab-safe_request_store/.gitignore
@@ -0,0 +1,11 @@
+/.bundle/
+/.yardoc
+/_yardoc/
+/coverage/
+/doc/
+/pkg/
+/spec/reports/
+/tmp/
+
+# rspec failure tracking
+.rspec_status
diff --git a/gems/gitlab-safe_request_store/.gitlab-ci.yml b/gems/gitlab-safe_request_store/.gitlab-ci.yml
new file mode 100644
index 00000000000..faf215536e2
--- /dev/null
+++ b/gems/gitlab-safe_request_store/.gitlab-ci.yml
@@ -0,0 +1,4 @@
+include:
+ - local: gems/gem.gitlab-ci.yml
+ inputs:
+ gem_name: "gitlab-safe_request_store" \ No newline at end of file
diff --git a/gems/gitlab-safe_request_store/.rspec b/gems/gitlab-safe_request_store/.rspec
new file mode 100644
index 00000000000..34c5164d9b5
--- /dev/null
+++ b/gems/gitlab-safe_request_store/.rspec
@@ -0,0 +1,3 @@
+--format documentation
+--color
+--require spec_helper
diff --git a/gems/gitlab-safe_request_store/.rubocop.yml b/gems/gitlab-safe_request_store/.rubocop.yml
new file mode 100644
index 00000000000..8c670b439d3
--- /dev/null
+++ b/gems/gitlab-safe_request_store/.rubocop.yml
@@ -0,0 +1,2 @@
+inherit_from:
+ - ../config/rubocop.yml
diff --git a/gems/gitlab-safe_request_store/Gemfile b/gems/gitlab-safe_request_store/Gemfile
new file mode 100644
index 00000000000..667a61d518e
--- /dev/null
+++ b/gems/gitlab-safe_request_store/Gemfile
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+source "https://rubygems.org"
+
+# Specify your gem's dependencies in gitlab-safe_request_store.gemspec
+gemspec
diff --git a/gems/gitlab-safe_request_store/Gemfile.lock b/gems/gitlab-safe_request_store/Gemfile.lock
new file mode 100644
index 00000000000..50ff694d7d5
--- /dev/null
+++ b/gems/gitlab-safe_request_store/Gemfile.lock
@@ -0,0 +1,103 @@
+PATH
+ remote: .
+ specs:
+ gitlab-safe_request_store (0.1.0)
+ request_store
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ activesupport (7.0.6)
+ concurrent-ruby (~> 1.0, >= 1.0.2)
+ i18n (>= 1.6, < 2)
+ minitest (>= 5.1)
+ tzinfo (~> 2.0)
+ ast (2.4.2)
+ coderay (1.1.3)
+ concurrent-ruby (1.2.2)
+ diff-lcs (1.5.0)
+ gitlab-styles (10.1.0)
+ rubocop (~> 1.50.2)
+ rubocop-graphql (~> 0.18)
+ rubocop-performance (~> 1.15)
+ rubocop-rails (~> 2.17)
+ rubocop-rspec (~> 2.22)
+ i18n (1.12.0)
+ concurrent-ruby (~> 1.0)
+ json (2.6.3)
+ method_source (1.0.0)
+ minitest (5.17.0)
+ parallel (1.22.1)
+ parser (3.2.2.3)
+ ast (~> 2.4.1)
+ racc
+ pry (0.14.2)
+ coderay (~> 1.1)
+ method_source (~> 1.0)
+ racc (1.6.2)
+ rack (3.0.4.1)
+ rainbow (3.1.1)
+ regexp_parser (2.7.0)
+ request_store (1.5.1)
+ rack (>= 1.4)
+ rexml (3.2.5)
+ rspec (3.12.0)
+ rspec-core (~> 3.12.0)
+ rspec-expectations (~> 3.12.0)
+ rspec-mocks (~> 3.12.0)
+ rspec-core (3.12.1)
+ rspec-support (~> 3.12.0)
+ rspec-expectations (3.12.2)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.12.0)
+ rspec-mocks (3.12.3)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.12.0)
+ rspec-support (3.12.0)
+ rubocop (1.50.2)
+ json (~> 2.3)
+ parallel (~> 1.10)
+ parser (>= 3.2.0.0)
+ rainbow (>= 2.2.2, < 4.0)
+ regexp_parser (>= 1.8, < 3.0)
+ rexml (>= 3.2.5, < 4.0)
+ rubocop-ast (>= 1.28.0, < 2.0)
+ ruby-progressbar (~> 1.7)
+ unicode-display_width (>= 2.4.0, < 3.0)
+ rubocop-ast (1.29.0)
+ parser (>= 3.2.1.0)
+ rubocop-capybara (2.18.0)
+ rubocop (~> 1.41)
+ rubocop-factory_bot (2.23.1)
+ rubocop (~> 1.33)
+ rubocop-graphql (0.19.0)
+ rubocop (>= 0.87, < 2)
+ rubocop-performance (1.18.0)
+ rubocop (>= 1.7.0, < 2.0)
+ rubocop-ast (>= 0.4.0)
+ rubocop-rails (2.20.2)
+ activesupport (>= 4.2.0)
+ rack (>= 1.1)
+ rubocop (>= 1.33.0, < 2.0)
+ rubocop-rspec (2.22.0)
+ rubocop (~> 1.33)
+ rubocop-capybara (~> 2.17)
+ rubocop-factory_bot (~> 2.22)
+ ruby-progressbar (1.11.0)
+ tzinfo (2.0.6)
+ concurrent-ruby (~> 1.0)
+ unicode-display_width (2.4.2)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ gitlab-safe_request_store!
+ gitlab-styles (~> 10.1.0)
+ pry
+ rspec (~> 3.0)
+ rubocop (~> 1.50)
+ rubocop-rspec (~> 2.22)
+
+BUNDLED WITH
+ 2.4.16
diff --git a/gems/gitlab-safe_request_store/README.md b/gems/gitlab-safe_request_store/README.md
new file mode 100644
index 00000000000..13c20d74364
--- /dev/null
+++ b/gems/gitlab-safe_request_store/README.md
@@ -0,0 +1,42 @@
+# Gitlab::SafeRequestStore
+
+A safer abstraction of `RequestStore` that comes with [`request_store` gem](https://github.com/steveklabnik/request_store).
+
+This gem works as a proxy to `RequestStore` allowing you to use the same interface even when the Request Store
+is not active. In this case a `NullStore` is being used under the hood providing no-ops when the Request Store
+is not active.
+
+## Usage
+
+When request store is active it works the same as `RequestStore`:
+
+```ruby
+Gitlab::SafeRequestStore.active? # => true
+Gitlab::SafeRequestStore[:test] = 123
+Gitlab::SafeRequestStore[:test] # => 123
+```
+
+When request store is not active it does nothing:
+
+```ruby
+Gitlab::SafeRequestStore.active? # => false
+Gitlab::SafeRequestStore[:test] = 123
+Gitlab::SafeRequestStore[:test] # => nil
+```
+
+You can enforce the request store to temporarily be active using:
+
+```ruby
+Gitlab::SafeRequestStore.active? # => false
+
+Gitlab::SafeRequestStore.ensure_request_store do
+ Gitlab::SafeRequestStore.active? # => true
+ # do something...
+end
+
+Gitlab::SafeRequestStore.active? # => false
+```
+
+## Development
+
+Follow the GitLab [gems development guidelines](../../doc/development/gems.md).
diff --git a/gems/gitlab-safe_request_store/gitlab-safe_request_store.gemspec b/gems/gitlab-safe_request_store/gitlab-safe_request_store.gemspec
new file mode 100644
index 00000000000..a685a1eb447
--- /dev/null
+++ b/gems/gitlab-safe_request_store/gitlab-safe_request_store.gemspec
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require_relative "lib/gitlab/safe_request_store/version"
+
+Gem::Specification.new do |spec|
+ spec.name = "gitlab-safe_request_store"
+ spec.version = Gitlab::SafeRequestStore::Version::VERSION
+ spec.authors = ["group::tenant-scale"]
+ spec.email = ["engineering@gitlab.com"]
+
+ spec.summary = "Wrapper for RequestStore"
+ spec.description = "Provides a safe interface for RequestStore even when it is not active."
+ spec.homepage = "https://gitlab.com/gitlab-org/gitlab/-/tree/master/gems/gitlab-safe_request_store"
+ spec.license = 'MIT'
+ spec.required_ruby_version = ">= 3.0"
+ spec.metadata["rubygems_mfa_required"] = "true"
+
+ spec.files = Dir['lib/**/*.rb']
+ spec.require_paths = ["lib"]
+
+ spec.add_runtime_dependency "request_store"
+
+ spec.add_development_dependency "gitlab-styles", "~> 10.1.0"
+ spec.add_development_dependency "pry"
+ spec.add_development_dependency "rspec", "~> 3.0"
+ spec.add_development_dependency "rubocop", "~> 1.50"
+ spec.add_development_dependency "rubocop-rspec", "~> 2.22"
+end
diff --git a/gems/gitlab-safe_request_store/lib/gitlab/safe_request_store.rb b/gems/gitlab-safe_request_store/lib/gitlab/safe_request_store.rb
new file mode 100644
index 00000000000..65594283fb8
--- /dev/null
+++ b/gems/gitlab-safe_request_store/lib/gitlab/safe_request_store.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require 'forwardable'
+
+require 'request_store'
+
+require_relative "safe_request_store/version"
+require_relative "safe_request_store/null_store"
+
+module Gitlab
+ module SafeRequestStore
+ NULL_STORE = NullStore.new
+
+ class << self
+ extend Forwardable
+
+ # These methods should always run directly against RequestStore
+ def_delegators :RequestStore, :clear!, :begin!, :end!, :active?
+
+ # These methods will run against NullStore if RequestStore is disabled
+ def_delegators :store, :read, :[], :write, :[]=, :exist?, :fetch, :delete
+
+ def store
+ if RequestStore.active?
+ RequestStore
+ else
+ NULL_STORE
+ end
+ end
+
+ # Access to the backing storage of the request store. This returns an object
+ # with `[]` and `[]=` methods that does not discard values.
+ #
+ # This can be useful if storage is needed for a delimited purpose, and the
+ # forgetful nature of the null store is undesirable.
+ def storage
+ store.store
+ end
+
+ # This method accept an options hash to be compatible with
+ # ActiveSupport::Cache::Store#write method. The options are
+ # not passed to the underlying cache implementation because
+ # RequestStore#write accepts only a key, and value params.
+ def write(key, value, _options = nil)
+ store.write(key, value)
+ end
+
+ def delete_if(&_block)
+ return unless RequestStore.active?
+
+ storage.delete_if { |k, _v| yield(k) }
+ end
+
+ def ensure_request_store(&block)
+ # Skip enabling the request store if it was already active. Whatever
+ # instantiated the request store first is responsible for clearing it
+ return yield if RequestStore.active?
+
+ enabling_request_store(&block)
+ end
+
+ private
+
+ def enabling_request_store
+ RequestStore.begin!
+ yield
+ ensure
+ RequestStore.end!
+ RequestStore.clear!
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-safe_request_store/lib/gitlab/safe_request_store/null_store.rb b/gems/gitlab-safe_request_store/lib/gitlab/safe_request_store/null_store.rb
new file mode 100644
index 00000000000..9a75ce6421c
--- /dev/null
+++ b/gems/gitlab-safe_request_store/lib/gitlab/safe_request_store/null_store.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module SafeRequestStore
+ # The methods `begin!`, `clear!`, and `end!` are not defined because they
+ # should only be called directly on `RequestStore`.
+ class NullStore
+ def store
+ {}
+ end
+
+ def active?
+ # no-op
+ end
+
+ def read(_key)
+ # no-op
+ end
+
+ def [](_key)
+ # no-op
+ end
+
+ def write(_key, value)
+ value
+ end
+
+ def []=(_key, value)
+ value
+ end
+
+ def exist?(_key)
+ false
+ end
+
+ def fetch(_key, &_block)
+ yield
+ end
+
+ def delete(key, &block)
+ yield(key) if block
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-safe_request_store/lib/gitlab/safe_request_store/version.rb b/gems/gitlab-safe_request_store/lib/gitlab/safe_request_store/version.rb
new file mode 100644
index 00000000000..c7eecf1efe0
--- /dev/null
+++ b/gems/gitlab-safe_request_store/lib/gitlab/safe_request_store/version.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module SafeRequestStore
+ module Version
+ VERSION = "0.1.0"
+ end
+ end
+end
diff --git a/gems/gitlab-safe_request_store/spec/gitlab/safe_request_store/null_store_spec.rb b/gems/gitlab-safe_request_store/spec/gitlab/safe_request_store/null_store_spec.rb
new file mode 100644
index 00000000000..a6bd4bba50f
--- /dev/null
+++ b/gems/gitlab-safe_request_store/spec/gitlab/safe_request_store/null_store_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::SafeRequestStore::NullStore do
+ let(:null_store) { described_class.new }
+
+ describe '#store' do
+ it 'returns an empty hash' do
+ expect(null_store.store).to eq({})
+ end
+ end
+
+ describe '#active?' do
+ it 'returns falsey' do
+ expect(null_store.active?).to be_falsey
+ end
+ end
+
+ describe '#read' do
+ it 'returns nil' do
+ expect(null_store.read('foo')).to be nil
+ end
+ end
+
+ describe '#[]' do
+ it 'returns nil' do
+ expect(null_store['foo']).to be nil
+ end
+ end
+
+ describe '#write' do
+ it 'returns the same value' do
+ expect(null_store.write('key', 'value')).to eq('value')
+ end
+ end
+
+ describe '#[]=' do
+ it 'returns the same value' do
+ expect(null_store['key'] = 'value').to eq('value')
+ end
+ end
+
+ describe '#exist?' do
+ it 'returns falsey' do
+ expect(null_store.exist?('foo')).to be_falsey
+ end
+ end
+
+ describe '#fetch' do
+ it 'returns the block result' do
+ expect(null_store.fetch('key') { 'block result' }).to eq('block result') # rubocop:disable Style/RedundantFetchBlock
+ end
+ end
+
+ describe '#delete' do
+ context 'when a block is given' do
+ it 'yields the key to the block' do
+ expect do |b|
+ null_store.delete('foo', &b)
+ end.to yield_with_args('foo')
+ end
+
+ it 'returns the block result' do
+ expect(null_store.delete('foo') { |_key| 'block result' }).to eq('block result')
+ end
+ end
+
+ context 'when a block is not given' do
+ it 'returns nil' do
+ expect(null_store.delete('foo')).to be nil
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-safe_request_store/spec/gitlab/safe_request_store_spec.rb b/gems/gitlab-safe_request_store/spec/gitlab/safe_request_store_spec.rb
new file mode 100644
index 00000000000..a171c50ca3e
--- /dev/null
+++ b/gems/gitlab-safe_request_store/spec/gitlab/safe_request_store_spec.rb
@@ -0,0 +1,281 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::SafeRequestStore do
+ it "has a version number" do
+ expect(described_class::Version::VERSION).not_to be nil
+ end
+
+ describe '.ensure_request_store' do
+ it 'starts a request store and yields control' do
+ expect(RequestStore).to receive(:begin!).ordered
+ expect(RequestStore).to receive(:end!).ordered
+ expect(RequestStore).to receive(:clear!).ordered
+
+ expect { |b| described_class.ensure_request_store(&b) }.to yield_control
+ end
+
+ it 'only starts a request store once when nested' do
+ expect(RequestStore).to receive(:begin!).ordered.once.and_call_original
+ expect(RequestStore).to receive(:end!).ordered.once.and_call_original
+ expect(RequestStore).to receive(:clear!).ordered.once.and_call_original
+
+ described_class.ensure_request_store do
+ expect { |b| described_class.ensure_request_store(&b) }.to yield_control
+ end
+ end
+ end
+
+ describe '.store' do
+ context 'when RequestStore is active', :enable_request_store do
+ it 'uses RequestStore' do
+ expect(described_class.store).to eq(RequestStore)
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'does not use RequestStore' do
+ expect(described_class.store).to be_a(described_class::NullStore)
+ end
+ end
+ end
+
+ describe '.begin!' do
+ context 'when RequestStore is active', :enable_request_store do
+ it 'uses RequestStore' do
+ expect(RequestStore).to receive(:begin!)
+
+ described_class.begin!
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'uses RequestStore' do
+ expect(RequestStore).to receive(:begin!)
+
+ described_class.begin!
+ end
+ end
+ end
+
+ describe '.clear!' do
+ context 'when RequestStore is active', :enable_request_store do
+ it 'uses RequestStore' do
+ expect(RequestStore).to receive(:clear!).once.and_call_original
+
+ described_class.clear!
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'uses RequestStore' do
+ expect(RequestStore).to receive(:clear!).and_call_original
+
+ described_class.clear!
+ end
+ end
+ end
+
+ describe '.end!' do
+ context 'when RequestStore is active', :enable_request_store do
+ it 'uses RequestStore' do
+ expect(RequestStore).to receive(:end!).once.and_call_original
+
+ described_class.end!
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'uses RequestStore' do
+ expect(RequestStore).to receive(:end!).and_call_original
+
+ described_class.end!
+ end
+ end
+ end
+
+ describe '.write' do
+ context 'when RequestStore is active', :enable_request_store do
+ it 'uses RequestStore' do
+ expect do
+ described_class.write('foo', true)
+ end.to change { described_class.read('foo') }.from(nil).to(true)
+ end
+
+ it 'does not pass the options hash to the underlying store implementation' do
+ expect(described_class.store).to receive(:write).with('foo', true)
+
+ described_class.write('foo', true, expires_in: 15)
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'does not use RequestStore' do
+ expect do
+ described_class.write('foo', true)
+ end.not_to change { described_class.read('foo') }.from(nil)
+ end
+
+ it 'does not pass the options hash to the underlying store implementation' do
+ expect(described_class.store).to receive(:write).with('foo', true)
+
+ described_class.write('foo', true, expires_in: 15)
+ end
+ end
+ end
+
+ describe '.[]=' do
+ context 'when RequestStore is active', :enable_request_store do
+ it 'uses RequestStore' do
+ expect do
+ described_class['foo'] = true
+ end.to change { described_class.read('foo') }.from(nil).to(true)
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'does not use RequestStore' do
+ expect do
+ described_class['foo'] = true
+ end.not_to change { described_class.read('foo') }.from(nil)
+ end
+ end
+ end
+
+ describe '.read' do
+ context 'when RequestStore is active', :enable_request_store do
+ it 'uses RequestStore' do
+ expect do
+ RequestStore.write('foo', true)
+ end.to change { described_class.read('foo') }.from(nil).to(true)
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'does not use RequestStore' do
+ expect do
+ RequestStore.write('foo', true)
+ end.not_to change { described_class.read('foo') }.from(nil)
+
+ RequestStore.clear! # Clean up
+ end
+ end
+ end
+
+ describe '.[]' do
+ context 'when RequestStore is active', :enable_request_store do
+ it 'uses RequestStore' do
+ expect do
+ RequestStore.write('foo', true)
+ end.to change { described_class['foo'] }.from(nil).to(true)
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'does not use RequestStore' do
+ expect do
+ RequestStore.write('foo', true)
+ end.not_to change { described_class['foo'] }.from(nil)
+
+ RequestStore.clear! # Clean up
+ end
+ end
+ end
+
+ describe '.exist?' do
+ context 'when RequestStore is active', :enable_request_store do
+ it 'uses RequestStore' do
+ expect do
+ RequestStore.write('foo', 'not nil')
+ end.to change { described_class.exist?('foo') }.from(false).to(true)
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'does not use RequestStore' do
+ expect do
+ RequestStore.write('foo', 'not nil')
+ end.not_to change { described_class.exist?('foo') }.from(false)
+
+ RequestStore.clear! # Clean up
+ end
+ end
+ end
+
+ describe '.fetch' do
+ context 'when RequestStore is active', :enable_request_store do
+ it 'uses RequestStore' do
+ expect do
+ described_class.fetch('foo') { 'block result' } # rubocop:disable Style/RedundantFetchBlock
+ end.to change { described_class.read('foo') }.from(nil).to('block result')
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'does not use RequestStore' do
+ RequestStore.clear! # Ensure clean
+
+ expect do
+ described_class.fetch('foo') { 'block result' } # rubocop:disable Style/RedundantFetchBlock
+ end.not_to change { described_class.read('foo') }.from(nil)
+
+ RequestStore.clear! # Clean up
+ end
+ end
+ end
+
+ describe '.delete' do
+ context 'when RequestStore is active', :enable_request_store do
+ it 'uses RequestStore' do
+ described_class.write('foo', true)
+
+ expect do
+ described_class.delete('foo')
+ end.to change { described_class.read('foo') }.from(true).to(nil)
+ end
+
+ context 'when given a block and the key exists' do
+ it 'does not execute the block' do
+ described_class.write('foo', true)
+
+ expect do |b|
+ described_class.delete('foo', &b)
+ end.not_to yield_control
+ end
+ end
+
+ context 'when given a block and the key does not exist' do
+ it 'yields the key and returns the block result' do
+ result = described_class.delete('foo') { |key| "#{key} block result" }
+
+ expect(result).to eq('foo block result')
+ end
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ before do
+ RequestStore.write('foo', true)
+ end
+
+ after do
+ RequestStore.clear! # Clean up
+ end
+
+ it 'does not use RequestStore' do
+ expect do
+ described_class.delete('foo')
+ end.not_to change { RequestStore.read('foo') }.from(true)
+ end
+
+ context 'when given a block' do
+ it 'yields the key and returns the block result' do
+ result = described_class.delete('foo') { |key| "#{key} block result" }
+
+ expect(result).to eq('foo block result')
+ end
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-safe_request_store/spec/spec_helper.rb b/gems/gitlab-safe_request_store/spec/spec_helper.rb
new file mode 100644
index 00000000000..08663dd7cb1
--- /dev/null
+++ b/gems/gitlab-safe_request_store/spec/spec_helper.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require "gitlab/safe_request_store"
+
+RSpec.configure do |config|
+ # Enable flags like --only-failures and --next-failure
+ config.example_status_persistence_file_path = ".rspec_status"
+
+ # Disable RSpec exposing methods globally on `Module` and `main`
+ config.disable_monkey_patching!
+
+ config.expect_with :rspec do |c|
+ c.syntax = :expect
+ end
+
+ config.around(:example, :enable_request_store) do |example|
+ ::Gitlab::SafeRequestStore.ensure_request_store { example.run }
+ end
+end