From 01eb9b2a97f47202daa4947b5dc1c7046065faa0 Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Mon, 26 Jun 2023 10:46:13 +0100 Subject: [PATCH] Make RSpec::Support.thread_local_data thread but not fiber local --- Changelog.md | 5 +++++ lib/rspec/support.rb | 10 ++++++++-- spec/rspec/support_spec.rb | 20 ++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index 551af9cc..f99a3658 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,11 @@ ### Development [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.12.0...main) +Bug Fixes: + +* Fix `RSpec::Support.thread_local_data` to be Thread local but not Fiber local. + (Jon Rowe, #581) + ### 3.12.0 / 2022-10-26 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.11.1...v3.12.0) Enhancements: diff --git a/lib/rspec/support.rb b/lib/rspec/support.rb index b85eae3c..4732f728 100644 --- a/lib/rspec/support.rb +++ b/lib/rspec/support.rb @@ -89,8 +89,14 @@ def self.class_of(object) end # A single thread local variable so we don't excessively pollute that namespace. - def self.thread_local_data - Thread.current[:__rspec] ||= {} + if RUBY_VERSION.to_f >= 2 + def self.thread_local_data + Thread.current.thread_variable_get(:__rspec) || Thread.current.thread_variable_set(:__rspec, {}) + end + else + def self.thread_local_data + Thread.current[:__rspec] ||= {} + end end # @api private diff --git a/spec/rspec/support_spec.rb b/spec/rspec/support_spec.rb index 2bb28351..75d784dd 100644 --- a/spec/rspec/support_spec.rb +++ b/spec/rspec/support_spec.rb @@ -186,6 +186,26 @@ def object.some_method end end + describe ".thread_local_data" do + it "contains data local to the current thread" do + RSpec::Support.thread_local_data[:__for_test] = :oh_hai + + Thread.new do + expect(RSpec::Support.thread_local_data).to eq({}) + end.join + end + + if defined?(Fiber) && RUBY_VERSION.to_f >= 2.0 + it "shares data across fibres" do + RSpec::Support.thread_local_data[:__for_test] = :oh_hai + + Fiber.new do + expect(RSpec::Support.thread_local_data[:__for_test]).to eq(:oh_hai) + end.resume + end + end + end + describe "failure notification" do before { @failure_notifier = RSpec::Support.failure_notifier } after { RSpec::Support.failure_notifier = @failure_notifier }