From 8b13c90d40816d41f353502f5b7b864bd9ffc824 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Tue, 23 Jul 2019 22:39:01 -0400 Subject: [PATCH] Fix turning off VCR not working when server thread already started When VCR is first used in the main (test) thread, it initializes a context, holding the status of whether VCR is turned off. When another thread is started (ie. app server), VCR initializes a context there by duplicating the main thread's context and linking to the main thread's context. If you turned off VCR in the main thread after it's context was duplicated to an additional thread, the additional thread wouldn't see the new turned off status (since it was only on the linked context), so it'd fail thinking VCR was still turned on but no cassette was inserted when a request was made. Now we check both the current thread's context, and the linked (main) thread's context to see if VCR is turned off, to ensure an app server thread can see when VCR is turned off on the main thread. This was most noticeable in Capybara tests with a JS driver where the app server thread was started once upon the first spec needing it, thus duplicating the main thread's context then, but if later specs turned off VCR, the app server thread never had it's context updated to reflect that, nor did it check the main thread's context to see if VCR was turned off there. --- lib/vcr.rb | 3 +++ spec/acceptance/threading_spec.rb | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/lib/vcr.rb b/lib/vcr.rb index 4e12cc4d..6801babb 100644 --- a/lib/vcr.rb +++ b/lib/vcr.rb @@ -308,6 +308,9 @@ def turn_on! # @see #turn_off! # @see #turned_off def turned_on? + linked_context = current_context[:linked_context] + return !linked_context[:turned_off] if linked_context + !context_value(:turned_off) end diff --git a/spec/acceptance/threading_spec.rb b/spec/acceptance/threading_spec.rb index 7f367389..6ad35d9e 100644 --- a/spec/acceptance/threading_spec.rb +++ b/spec/acceptance/threading_spec.rb @@ -29,5 +29,34 @@ def recorded_content_for(name) expect(recorded_content_for("search") + recorded_content_for("foo")).to include("query: thread", "FOO!") end + + it 'can turn off VCR after another thread has started and affect the new thread' do + # Trigger context in main thread + VCR.turned_on? + + thread = Thread.start do + # Trigger VCR to dup context to this new thread, linked to main thread + VCR.turned_on? + + # Stop processing this thread so we can turn off VCR on the main thread + Thread.stop + + # This request should be made after VCR is turned off on the main thread + Excon.get "http://localhost:#{VCR::SinatraApp.port}" + end + + # Ensure the other thread has a chance to stop before we proceed? + sleep 1 + + VCR.turned_off do + # Now that VCR is turned off, we can resume our other thread + thread.wakeup + + # Ensure the other thread has a chance to resume before we proceed? + sleep 1 + end + + thread.join + end end end