Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

meck:unload/0 sometimes crashes #48

Closed
legoscia opened this issue Nov 4, 2011 · 3 comments
Closed

meck:unload/0 sometimes crashes #48

legoscia opened this issue Nov 4, 2011 · 3 comments
Labels

Comments

@legoscia
Copy link
Contributor

legoscia commented Nov 4, 2011

Every now and then, meck:unload/0 crashes with not_mocked for me. It seems to be a race condition: unload/0 passes everything in registered() that locks like a mock to unload_if_mocked, but if the mock module has already been unloaded at that point (due to having been mocked by a now dead process), a not_mocked error is raised and the remaining modules are not unmocked.

I could reproduce it with this Proper property (because it runs the test enough times to make the race condition more likely):

-module(foo).

-compile(export_all).
-include_lib("proper/include/proper.hrl").

prop_unload() ->
    ?FORALL({Wait1, Wait2}, {nat(), nat()},
            begin
                {_, Ref} = spawn_monitor(fun() ->
                                                 timer:sleep(Wait1),
                                                 meck:new(foobar)
                                         end),
                timer:sleep(Wait1 + Wait2),
                meck:unload(),
                receive {'DOWN', Ref, process, _Pid, _Reason} -> ok end,
                true
            end).

Failure looks like this:

22> proper:quickcheck(foo:prop_unload()).
..
=ERROR REPORT==== 4-Nov-2011::14:16:36 ===
Error in process <0.1056.0> with exit value: {{already_started,<0.1054.0>},[{meck,new,[foobar,[]]}]}

......!
Failed: After 9 test(s).
An exception was raised: error:{not_mocked,foobar}.
Stacktrace: [{meck,gen_server,3},
             {meck,unload,1},
             {meck,unload_if_mocked,2},
             {lists,foldl,3},
             {foo,'-prop_unload/0-fun-1-',1}].
{4,4}

Shrinking .(1 time(s))
{1,4}
false

This patch seems to fix the problem:

diff --git a/meck/src/meck.erl b/meck/src/meck.erl
--- a/meck/src/meck.erl
+++ b/meck/src/meck.erl
@@ -400,7 +400,8 @@ unload_if_mocked(P, L) when length(P) > 5 ->
     case lists:split(length(P) - 5, P) of
         {Name, "_meck"} ->
             Mocked = list_to_existing_atom(Name),
-            unload(Mocked),
+            catch call(Mocked, stop),
+            wait_for_exit(Mocked),
             [Mocked|L];
         _Else ->
             L
@eproxus
Copy link
Owner

eproxus commented Nov 4, 2011

The fix should probably be try call(Mocked, stop) catch exit:{not_mocked, Mocked} -> ok end?

@legoscia
Copy link
Contributor Author

legoscia commented Nov 4, 2011

Right, that's a nicer fix (except that it should be error instead of exit ☺). I've now convinced myself that this is the best way to do it:

diff --git a/meck/src/meck.erl b/meck/src/meck.erl
--- a/meck/src/meck.erl
+++ b/meck/src/meck.erl
@@ -400,7 +400,11 @@ unload_if_mocked(P, L) when length(P) > 5 ->
     case lists:split(length(P) - 5, P) of
         {Name, "_meck"} ->
             Mocked = list_to_existing_atom(Name),
-            unload(Mocked),
+            try
+                unload(Mocked)
+            catch error:{not_mocked, Mocked} ->
+                    ok
+            end,
             [Mocked|L];
         _Else ->
             L

This also avoids monitoring the dead process.

@eproxus eproxus closed this as completed in 7aca52a Nov 4, 2011
@eproxus
Copy link
Owner

eproxus commented Nov 4, 2011

Didn't add any proper property for this yet, so unfortunately there's no coverage for 4th added line in the patch.

@eproxus eproxus added the bug label Jun 28, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants