Open myronmarston opened 8 years ago
Thanks for the extensive report and analysis, the 3 points you mentioned makes sense. Is there any ways you can try (or provide sample code?). If you can provide PR, that would be great too, though.
I tried extracting something isolated and failed, sadly, so there's something going on I don't understand and I can't really provide you with our entire codebase. I'll keep an eye out to see if it happens again and can extract something at that time.
Hi there,
@myronmarston Have you found a workaround to this issue ?
On my project, it's happening when I have a GenServer handle_call
or handle_cast
spawning a process that will have to to an HTTP request to HTTPoison, faked by ExVCR. And same as @myronmarston it's happening randomly.
For now, I do a try catch on that error to having it removed to the tests. But that's not a solution :
spawn(fn ->
try do
function_using_http_poison
rescue
e in HTTPoison.Error ->
nil
end
@myronmarston Have you found a workaround to this issue ?
Nope.
I'm having the same problem when using HTTPoison.
Something similar to https://github.com/parroty/exvcr/issues/53 it happens when we have multiple requests in the test suite. Using HTTPoison and same issue.
i have a similar issue with parallel requests being made https://github.com/parroty/exvcr/issues/127 (sorry i just found this issue), i think both are related. i also added a minimum code sample of what i'm doing.
It seems that network calls from spawned processes are not mocked at all. Upon switching off my wifi and running this test when a cassette is already populated, I receive an error which indicates the cassette was ignored and that it tried to make a network request.
The behaviour was the same even after turning on the global_mock config
defmodule Api.SomeTest.Test do
use ExUnit.Case, async: false
use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
test "can get" do
parent_pid = self()
use_cassette "get_example_dotcom" do
Process.spawn(
fn ->
res = HTTPoison.get("https://example.com")
send(parent_pid, res)
end,
[:link]
)
end
assert_receive {:ok, %{status_code: 200}}, 5000
end
end
1) test can get (Api.SomeTest.Test)
test/api/get_example_test.exs:5
Assertion failed, no matching message after 5000ms
Showing 1 of 1 message in the mailbox
code: assert_receive {:ok, %{status_code: 200}}
mailbox:
pattern: {:ok, %{status_code: 200}}
value: {:error, %HTTPoison.Error{__exception__: true, id: nil, reason: :nxdomain}}
stacktrace:
test/api/get_example_test.exs:18: (test)
Finished in 5.1 seconds (0.00s async, 5.1s sync)
1 test, 1 failure
We've been using ExVCR for a while and for the most part it's working well for us. However, I've spent a few hours using it in a certain situation where it's not working correctly at all and is producing inconsistent results. Here's our setup:
barbosa_client
(a simple HTTP client for an internal service using httpoison) andapi
(a phoenix app).barbosa_client
api
, we have a phoenix channel that:get_data
eventbarbosa_client
. The others read data off the file system or from a SQL DB)I've tried to use ExVCR in the test of the phoenix channel in
api
and it's not working right at all. Specifically, the results are inconsistent -- I ran it a bunch of times to get it to record the interaction and I got several different results. Eventually, I got it to record, but now it plays back inconsistently. Occasionally (less than 10%) of the time, but the rest of the time it gets one of a few different failures.Here are the different failures I see (both when recording and when trying to play back). Most common is this:
Some process exited, but it provides no detail to understand what happen, unfortunately. I occasionally see this:
Once I get this head-scratcher:
What's odd about this is that
link_opportunities_acceptance_test.json
is not used in this test -- it's used in a completely different test in a completely different file.I've confirmed that we have
async: false
in all of our tests that use ExVCR so it can't be async tests at fault (also, adding--max-cases 1
to prevent any async tests resulted in the same inconsistent weirdness).I've tried isolating this to a simple reproducible example I can provide for you but haven't yet gotten that (sorry), but I could perhaps spend more time on that if you really need it.
I've been assuming the parallel spawned processes in the channel are at fault but (a) only one of them makes an HTTP request so there are no parallel requests happening and (b) when I move the request into a spawned process in other tests where ExVCR is working it keep working just fine...so that may be a red herring.
I did a bit of looking around the ExVCR source and noticed some places where I'd expect there to be race conditions if ExVCR was used for a test of code that makes parallel requests. I'm not sure if these are related or not, but thought I'd mention them all the same:
get
and theset
call the GenServer could respond to another message, right? I think this could be fixed by moving the logic behind adefcall
so that it all happens within the GenServer, ensuring it happens synchronously.get
andappend
and I think this logic should happen within the GenServer instead of in the client process.get
gen sever calls in themap
followed by aset
at the end and again, the genserver state could change in the meantime. (Also, if theupdater
orfinder
functions use any GenServers they could lead to race conditions as well).To prevent race conditions, I'd expect any operation that needs to be treated atomically to happen within a single GenServer.
Thanks!