summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul J. Davis <paul.joseph.davis@gmail.com>2017-07-17 14:38:44 -0500
committerPaul J. Davis <paul.joseph.davis@gmail.com>2017-07-18 11:47:57 -0500
commitc8f340e11c8fb34c960e98309bd514df0bd7b222 (patch)
treea85ac127867a62e7cc7ea2530f331ea59bf44016
parent0bea3a40c230e9a7f7932d4f97a5f441287bdb78 (diff)
downloadcouchdb-680-fix-couchdb-1283-test.tar.gz
Simplify regression test for COUCHDB-1283680-fix-couchdb-1283-test
The previous version of this test relied on trying to bump into the all_dbs_active error from the couch_server LRU. This proves to be rather difficult to reliably provide assertions on behavior. In hindsight all we really care about is that the compactor holds a monitor against the database and then we can trust couch_server will not evict anything that is actively monitored. Fixes #680
-rw-r--r--src/couch/test/couchdb_views_tests.erl170
1 files changed, 21 insertions, 149 deletions
diff --git a/src/couch/test/couchdb_views_tests.erl b/src/couch/test/couchdb_views_tests.erl
index 494d13bc1..616a3c8a4 100644
--- a/src/couch/test/couchdb_views_tests.erl
+++ b/src/couch/test/couchdb_views_tests.erl
@@ -117,7 +117,14 @@ view_group_shutdown_test_() ->
"View group shutdown",
{
setup,
- fun test_util:start_couch/0, fun test_util:stop_couch/1,
+ fun() ->
+ meck:new(couch_mrview_index, [passthrough]),
+ test_util:start_couch()
+ end,
+ fun(Ctx) ->
+ test_util:stop_couch(Ctx),
+ meck:unload()
+ end,
[couchdb_1283()]
}
}.
@@ -342,74 +349,29 @@ couchdb_1283() ->
ok = populate_db(MDb1, 100, 100),
query_view(MDb1#db.name, "foo", "foo"),
ok = couch_db:close(MDb1),
- % monitor db and index pids
- {ok, DDPid} = couch_index_server:get_index(
- couch_mrview_index, MDb1#db.name, <<"_design/foo">>),
-
- % Our query could have run after a partial update
- % so we need to make sure that the updater has
- % exited and released its monitor on the database
- % fd.
- wait_for_updater_exit(DDPid),
-
- DesignDocMonRef = erlang:monitor(process, DDPid),
- DatabaseMonRef = erlang:monitor(process, MDb1#db.main_pid),
-
- {ok, Db1} = couch_db:create(?tempdb(), [?ADMIN_CTX]),
- ok = couch_db:close(Db1),
- {ok, Db2} = couch_db:create(?tempdb(), [?ADMIN_CTX]),
- ok = couch_db:close(Db2),
- {ok, Db3} = couch_db:create(?tempdb(), [?ADMIN_CTX]),
- ok = couch_db:close(Db3),
-
- wait_for_process_shutdown(DatabaseMonRef, killed,
- {reason, "Failure waiting for db shutdown"}),
- wait_for_process_shutdown(DesignDocMonRef, normal,
- {reason, "Failure waiting for view index shutdown"}),
-
- Writer1 = spawn_writer(Db1#db.name),
- Writer2 = spawn_writer(Db2#db.name),
-
- ?assert(is_process_alive(Writer1)),
- ?assert(is_process_alive(Writer2)),
- ?assertEqual(ok, get_writer_status(Writer1)),
- ?assertEqual(ok, get_writer_status(Writer2)),
-
- %% Below we do exactly the same as couch_mrview:compact holds inside
- %% because we need have access to compaction Pid, not a Ref.
- %% {ok, MonRef} = couch_mrview:compact(MDb1#db.name, <<"_design/foo">>,
- %% [monitor]),
{ok, Pid} = couch_index_server:get_index(
couch_mrview_index, MDb1#db.name, <<"_design/foo">>),
+
+ % Start and pause compacton
{ok, CPid} = gen_server:call(Pid, compact),
- %% By suspending compaction process we ensure that compaction won't get
- %% finished too early to make get_writer_status assertion fail.
+ meck:wait(couch_mrview_index, compact, ['_', '_', '_'], 1000),
erlang:suspend_process(CPid),
- MonRef = erlang:monitor(process, CPid),
- Writer3 = spawn_writer(Db3#db.name),
- ?assert(is_process_alive(Writer3)),
- ?assertEqual({error, all_dbs_active}, get_writer_status(Writer3)),
+ CRef = erlang:monitor(process, CPid),
+ ?assert(is_process_alive(CPid)),
- ?assert(is_process_alive(Writer1)),
- ?assert(is_process_alive(Writer2)),
- ?assert(is_process_alive(Writer3)),
+ % Make sure that a compaction process takes a monitor
+ % on the database's main_pid
+ ?assertEqual(true, lists:member(CPid, couch_db:monitored_by(MDb1))),
- %% Resume compaction
+ % Finish compaction to and make sure the monitor
+ % disappears
erlang:resume_process(CPid),
- wait_for_process_shutdown(MonRef, normal,
+ wait_for_process_shutdown(CRef, normal,
{reason, "Failure compacting view group"}),
- ?assertEqual(ok, writer_try_again(Writer3)),
- ?assertEqual(ok, get_writer_status(Writer3)),
-
- ?assert(is_process_alive(Writer1)),
- ?assert(is_process_alive(Writer2)),
- ?assert(is_process_alive(Writer3)),
-
- ?assertEqual(ok, stop_writer(Writer1)),
- ?assertEqual(ok, stop_writer(Writer2)),
- ?assertEqual(ok, stop_writer(Writer3))
+ % Make sure that the monitor was removed
+ ?assertEqual(false, lists:member(CPid, couch_db:monitored_by(MDb1)))
end).
wait_for_process_shutdown(Pid, ExpectedReason, Error) ->
@@ -636,96 +598,6 @@ wait_view_compact_done(DbName, DDocId, N) ->
wait_view_compact_done(DbName, DDocId, N - 1)
end.
-% This is a bit of a dirty hack fishing through various
-% state records but at least its better than putting
-% a sleep on it and calling it fixed.
-wait_for_updater_exit(DDPid) ->
- % #st record from couch_index.erl
- IdxState = sys:get_state(DDPid),
- UpdaterPid = element(4, IdxState),
-
- % #st record from couch_index_updater.erl
- UpdaterState = sys:get_state(UpdaterPid),
- RunnerPid = element(4, UpdaterState),
-
- % RunnerPid can be nil, undefined, or a pid so
- % just check if its a pid and wait on it to
- % exit
- if not is_pid(RunnerPid) -> ok; true ->
- Ref = erlang:monitor(process, RunnerPid),
- receive {'DOWN', Ref, _, _, _} -> ok end
- end.
-
-spawn_writer(DbName) ->
- Parent = self(),
- spawn(fun() ->
- process_flag(priority, high),
- writer_loop(DbName, Parent)
- end).
-
-get_writer_status(Writer) ->
- Ref = make_ref(),
- Writer ! {get_status, Ref},
- receive
- {db_open, Ref} ->
- ok;
- {db_open_error, Error, Ref} ->
- Error
- after ?TIMEOUT ->
- timeout
- end.
-
-writer_try_again(Writer) ->
- Ref = make_ref(),
- Writer ! {try_again, Ref},
- receive
- {ok, Ref} ->
- ok
- after ?TIMEOUT ->
- timeout
- end.
-
-stop_writer(Writer) ->
- Ref = make_ref(),
- Writer ! {stop, Ref},
- receive
- {ok, Ref} ->
- ok
- after ?TIMEOUT ->
- erlang:error({assertion_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {reason, "Timeout on stopping process"}]})
- end.
-
-writer_loop(DbName, Parent) ->
- case couch_db:open_int(DbName, []) of
- {ok, Db} ->
- writer_loop_1(Db, Parent);
- Error ->
- writer_loop_2(DbName, Parent, Error)
- end.
-
-writer_loop_1(Db, Parent) ->
- receive
- {get_status, Ref} ->
- Parent ! {db_open, Ref},
- writer_loop_1(Db, Parent);
- {stop, Ref} ->
- ok = couch_db:close(Db),
- Parent ! {ok, Ref}
- end.
-
-writer_loop_2(DbName, Parent, Error) ->
- receive
- {get_status, Ref} ->
- Parent ! {db_open_error, Error, Ref},
- writer_loop_2(DbName, Parent, Error);
- {try_again, Ref} ->
- Parent ! {ok, Ref},
- writer_loop(DbName, Parent)
- end.
-
read_header(File) ->
{ok, Fd} = couch_file:open(File),
{ok, {_Sig, Header}} = couch_file:read_header(Fd),