This is an automated email from the ASF dual-hosted git repository. vatamane pushed a commit to branch fix-stream-tests-flaky-failure in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit 6dc62bb762665b53daf16903ccc7f4decbf81dfc Author: Nick Vatamaniuc <[email protected]> AuthorDate: Mon Oct 16 17:44:12 2023 -0400 Fix flaky couch_stream test On MacOS runner this test can be flaky. On slower workers StreamPid would usually be killed by the time we check is_process_alive/1, however on MacOS it has failed at least once with: ``` module 'couch_stream_tests' CouchDB stream tests couch_stream_tests:124: -should_stop_on_normal_exit_of_stream_opener/1-fun-3-...*failed* in function couch_stream_tests:'-should_stop_on_normal_exit_of_stream_opener/1-fun-3-'/1 (test/eunit/couch_stream_tests.erl, line 124) in call from eunit_test:run_testfun/1 (eunit_test.erl, line 71) [...] **error:{assert,[{module,couch_stream_tests}, {line,124}, {expression,"not ( is_process_alive ( StreamPid ) )"}, {expected,true}, {value,false}]} ``` To fix it, ensure we wait for the process to die before asserting it's dead. It's a bit redundant to assert it's gone, but we leave that in the test mostly to make it obvious what we're after. If the process refuses to die the test will most likely fail a timeout. While we're at it, modernize the test suite to use the standard `?TDEF_FE` macros. In some cases we were running the test code in the setup phase instead of the test itself (`_assert...` vs `assert...` calls), so this should fix that as well. --- src/couch/test/eunit/couch_stream_tests.erl | 41 ++++++++++++++++------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/couch/test/eunit/couch_stream_tests.erl b/src/couch/test/eunit/couch_stream_tests.erl index 4146a9139..eab99a7cb 100644 --- a/src/couch/test/eunit/couch_stream_tests.erl +++ b/src/couch/test/eunit/couch_stream_tests.erl @@ -36,45 +36,45 @@ stream_test_() -> fun setup/0, fun teardown/1, [ - fun should_write/1, - fun should_write_consecutive/1, - fun should_write_empty_binary/1, - fun should_return_file_pointers_on_close/1, - fun should_return_stream_size_on_close/1, - fun should_return_valid_pointers/1, - fun should_recall_last_pointer_position/1, - fun should_stream_more_with_4K_chunk_size/1, - fun should_stop_on_normal_exit_of_stream_opener/1 + ?TDEF_FE(should_write), + ?TDEF_FE(should_write_consecutive), + ?TDEF_FE(should_write_empty_binary), + ?TDEF_FE(should_return_file_pointers_on_close), + ?TDEF_FE(should_return_stream_size_on_close), + ?TDEF_FE(should_return_valid_pointers), + ?TDEF_FE(should_recall_last_pointer_position), + ?TDEF_FE(should_stream_more_with_4K_chunk_size), + ?TDEF_FE(should_stop_on_normal_exit_of_stream_opener) ] } } }. should_write({_, Stream}) -> - ?_assertEqual(ok, couch_stream:write(Stream, <<"food">>)). + ?assertEqual(ok, couch_stream:write(Stream, <<"food">>)). should_write_consecutive({_, Stream}) -> couch_stream:write(Stream, <<"food">>), - ?_assertEqual(ok, couch_stream:write(Stream, <<"foob">>)). + ?assertEqual(ok, couch_stream:write(Stream, <<"foob">>)). should_write_empty_binary({_, Stream}) -> - ?_assertEqual(ok, couch_stream:write(Stream, <<>>)). + ?assertEqual(ok, couch_stream:write(Stream, <<>>)). should_return_file_pointers_on_close({_, Stream}) -> couch_stream:write(Stream, <<"foodfoob">>), {NewEngine, _, _, _, _} = couch_stream:close(Stream), {ok, Ptrs} = couch_stream:to_disk_term(NewEngine), - ?_assertEqual([{0, 8}], Ptrs). + ?assertEqual([{0, 8}], Ptrs). should_return_stream_size_on_close({_, Stream}) -> couch_stream:write(Stream, <<"foodfoob">>), {_, Length, _, _, _} = couch_stream:close(Stream), - ?_assertEqual(8, Length). + ?assertEqual(8, Length). should_return_valid_pointers({_Fd, Stream}) -> couch_stream:write(Stream, <<"foodfoob">>), {NewEngine, _, _, _, _} = couch_stream:close(Stream), - ?_assertEqual(<<"foodfoob">>, read_all(NewEngine)). + ?assertEqual(<<"foodfoob">>, read_all(NewEngine)). should_recall_last_pointer_position({Fd, Stream}) -> couch_stream:write(Stream, <<"foodfoob">>), @@ -89,7 +89,7 @@ should_recall_last_pointer_position({Fd, Stream}) -> {ok, Ptrs} = couch_stream:to_disk_term(NewEngine), [{ExpPtr, 20}] = Ptrs, AllBits = iolist_to_binary([OneBits, ZeroBits]), - ?_assertEqual(AllBits, read_all(NewEngine)). + ?assertEqual(AllBits, read_all(NewEngine)). should_stream_more_with_4K_chunk_size({Fd, _}) -> {ok, Stream} = couch_stream:open(?ENGINE(Fd), [{buffer_size, 4096}]), @@ -104,11 +104,11 @@ should_stream_more_with_4K_chunk_size({Fd, _}) -> ), {NewEngine, Length, _, _, _} = couch_stream:close(Stream), {ok, Ptrs} = couch_stream:to_disk_term(NewEngine), - ?_assertMatch({[{0, 4100}, {4106, 1020}], 5120}, {Ptrs, Length}). + ?assertMatch({[{0, 4100}, {4106, 1020}], 5120}, {Ptrs, Length}). should_stop_on_normal_exit_of_stream_opener({Fd, _}) -> RunnerPid = self(), - OpenerPid = spawn( + {OpenerPid, OpenerRef} = spawn_monitor( fun() -> {ok, StreamPid} = couch_stream:open(?ENGINE(Fd)), RunnerPid ! {pid, StreamPid} @@ -119,9 +119,12 @@ should_stop_on_normal_exit_of_stream_opener({Fd, _}) -> {pid, StreamPid0} -> StreamPid0 end, % Confirm the validity of the test by verifying the stream opener has died + receive {'DOWN', OpenerRef, _, _, _} -> ok end, ?assertNot(is_process_alive(OpenerPid)), % Verify the stream itself has also died - ?_assertNot(is_process_alive(StreamPid)). + StreamRef = erlang:monitor(process, StreamPid), + receive {'DOWN', StreamRef, _, _, _} -> ok end, + ?assertNot(is_process_alive(StreamPid)). read_all(Engine) -> Data = couch_stream:foldl(Engine, fun(Bin, Acc) -> [Bin, Acc] end, []),
