blob: 4310157eb5a480502fa5cc4ffd0a4b822ea59131 [file] [log] [blame]
% Licensed under the Apache License, Version 2.0 (the "License"); you may not
% use this file except in compliance with the License. You may obtain a copy of
% the License at
%
% http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
% License for the specific language governing permissions and limitations under
% the License.
-module(couch_mrview_ddoc_updated_tests).
-include_lib("couch/include/couch_eunit.hrl").
-include_lib("couch/include/couch_db.hrl").
-define(TIMEOUT, 1000).
setup() ->
Name = ?tempdb(),
couch_server:delete(Name, [?ADMIN_CTX]),
{ok, Db} = couch_db:create(Name, [?ADMIN_CTX]),
DDoc = couch_doc:from_json_obj({[
{<<"_id">>, <<"_design/bar">>},
{<<"views">>, {[
{<<"baz">>, {[
{<<"map">>, <<
"function(doc) {\n"
" emit(doc.val, doc.val);\n"
"}"
>>}
]}}
]}}
]}),
[Doc1 | Docs999] = couch_mrview_test_util:make_docs(map, 100),
{ok, _} = couch_db:update_docs(Db, [DDoc, Doc1], []),
{ok, Db2} = couch_db:reopen(Db),
% run a query with 1 doc to initialize couch_index process
CB = fun
({row, _}, Count) -> {ok, Count+1};
(_, Count) -> {ok, Count}
end,
{ok, _} =
couch_mrview:query_view(Db2, <<"_design/bar">>, <<"baz">>, [], CB, 0),
meck:new(couch_index_updater, [passthrough]),
meck:expect(couch_index_updater, update, fun(Idx, Mod, IdxSt) ->
timer:sleep(5000),
meck:passthrough([Idx, Mod, IdxSt])
end),
% add more docs
{ok, _} = couch_db:update_docs(Db2, Docs999, []),
{ok, Db3} = couch_db:reopen(Db2),
Db3.
teardown(Db) ->
meck:unload(couch_index_updater),
couch_db:close(Db),
couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
ddoc_update_test_() ->
{
"Check ddoc update actions",
{
setup,
fun test_util:start_couch/0, fun test_util:stop_couch/1,
{
foreach,
fun setup/0, fun teardown/1,
[
fun check_indexing_stops_on_ddoc_change/1
]
}
}
}.
check_indexing_stops_on_ddoc_change(Db) ->
?_test(begin
DDocID = <<"_design/bar">>,
IndexesBefore = get_indexes_by_ddoc(DDocID, 1),
?assertEqual(1, length(IndexesBefore)),
AliveBefore = lists:filter(fun erlang:is_process_alive/1, IndexesBefore),
?assertEqual(1, length(AliveBefore)),
{ok, DDoc} = couch_db:open_doc(Db, DDocID, [ejson_body, ?ADMIN_CTX]),
DDocJson2 = couch_doc:from_json_obj({[
{<<"_id">>, DDocID},
{<<"_deleted">>, true},
{<<"_rev">>, couch_doc:rev_to_str(DDoc#doc.revs)}
]}),
% spawn a process for query
Self = self(),
QPid = spawn(fun() ->
{ok, Result} = couch_mrview:query_view(
Db, <<"_design/bar">>, <<"baz">>, []),
Self ! {self(), Result}
end),
% while indexing for the query is in progress, delete DDoc
{ok, _} = couch_db:update_doc(Db, DDocJson2, []),
receive
{QPid, Msg} ->
?assertEqual(Msg, ddoc_updated)
after ?TIMEOUT ->
erlang:error(
{assertion_failed, [{module, ?MODULE}, {line, ?LINE},
{reason, "test failed"}]})
end,
%% assert that previously running indexes are gone
IndexesAfter = get_indexes_by_ddoc(DDocID, 0),
?assertEqual(0, length(IndexesAfter)),
AliveAfter = lists:filter(fun erlang:is_process_alive/1, IndexesBefore),
?assertEqual(0, length(AliveAfter))
end).
get_indexes_by_ddoc(DDocID, N) ->
Indexes = test_util:wait(fun() ->
Indxs = ets:match_object(
couchdb_indexes_by_db, {'$1', {DDocID, '$2'}}),
case length(Indxs) == N of
true ->
Indxs;
false ->
wait
end
end),
lists:foldl(fun({DbName, {_DDocID, Sig}}, Acc) ->
case ets:lookup(couchdb_indexes_by_sig, {DbName, Sig}) of
[{_, Pid}] -> [Pid|Acc];
_ -> Acc
end
end, [], Indexes).