blob: 5fa4bc90f96fccd66da0a5b64e47c93a1d237958 [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(dreyfus_purge_test).
-include_lib("couch/include/couch_db.hrl").
-include_lib("dreyfus/include/dreyfus.hrl").
-include_lib("couch/include/couch_eunit.hrl").
-include_lib("mem3/include/mem3.hrl").
-export([test_purge_single/0, test_purge_multiple/0, test_purge_multiple2/0,
test_purge_conflict/0, test_purge_conflict2/0, test_purge_conflict3/0, test_purge_conflict4/0,
test_purge_update/0, test_purge_update2/0,
test_delete/0, test_delete_purge_conflict/0, test_delete_conflict/0,
test_all/0]).
-export([test_verify_index_exists1/0, test_verify_index_exists2/0, test_verify_index_exists_failed/0,
test_local_doc/0, test_delete_local_doc/0, test_purge_search/0]).
-compile(export_all).
test_all() ->
test_purge_single(),
test_purge_multiple(),
test_purge_multiple2(),
test_purge_conflict(),
test_purge_conflict2(),
test_purge_conflict3(),
test_purge_conflict4(),
test_purge_update(),
test_purge_update2(),
test_delete(),
test_delete_purge_conflict(),
test_delete_conflict(),
test_verify_index_exists1(),
test_verify_index_exists2(),
test_verify_index_exists_failed(),
test_delete_local_doc(),
test_local_doc(),
test_purge_search(),
ok.
test_purge_single() ->
DbName = db_name(),
create_db_docs(DbName),
{ok, _, HitCount1, _, _, _} = dreyfus_search(DbName, <<"apple">>),
?assertEqual(HitCount1, 1),
purge_docs(DbName, [<<"apple">>]),
{ok, _, HitCount2, _, _, _} = dreyfus_search(DbName, <<"apple">>),
?assertEqual(HitCount2, 0),
delete_db(DbName),
ok.
test_purge_multiple() ->
Query = <<"color:red">>,
%create the db and docs
DbName = db_name(),
create_db_docs(DbName),
%first search request
{ok, _, HitCount1, _, _, _} = dreyfus_search(DbName, Query),
?assertEqual(HitCount1, 5),
%purge 5 docs
purge_docs(DbName, [<<"apple">>, <<"tomato">>, <<"cherry">>, <<"haw">>,
<<"strawberry">>]),
%second search request
{ok, _, HitCount2, _, _, _} = dreyfus_search(DbName, Query),
?assertEqual(HitCount2, 0),
%delete the db
delete_db(DbName),
ok.
test_purge_multiple2() ->
%create the db and docs
DbName = db_name(),
create_db_docs(DbName),
Query = <<"color:red">>,
%first search request
{ok, _, HitCount1, _, _, _} = dreyfus_search(DbName, Query),
?assertEqual(HitCount1, 5),
%purge 2 docs
purge_docs(DbName, [<<"apple">>, <<"tomato">>]),
%second search request
{ok, _, HitCount2, _, _, _} = dreyfus_search(DbName, Query),
?assertEqual(HitCount2, 3),
%purge 2 docs
purge_docs(DbName, [<<"cherry">>, <<"haw">>]),
%third search request
{ok, _, HitCount3, _, _, _} = dreyfus_search(DbName, Query),
?assertEqual(HitCount3, 1),
%delete the db
delete_db(DbName),
ok.
test_purge_conflict() ->
%create dbs and docs
SourceDbName = db_name(),
timer:sleep(2000),
TargetDbName = db_name(),
create_db_docs(SourceDbName),
create_db_docs(TargetDbName, <<"green">>),
%first search
{ok, _, RedHitCount1, _RedHits1, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount1, _GreenHits1, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(5, RedHitCount1 + GreenHitCount1),
%do replicate and make conflicted docs
{ok, _} = fabric:update_doc(<<"_replicator">>, make_replicate_doc(
SourceDbName, TargetDbName), [?ADMIN_CTX]),
%%check doc version
wait_for_replicate(TargetDbName, [<<"apple">>, <<"tomato">>, <<"cherry">>,
<<"haw">>, <<"strawberry">>], 2, 5),
%second search
{ok, _, RedHitCount2, _RedHits2, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount2, _GreenHits2, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(5, RedHitCount2 + GreenHitCount2),
purge_docs(TargetDbName, [<<"apple">>, <<"tomato">>, <<"cherry">>, <<"haw">>,
<<"strawberry">>]),
%third search
{ok, _, RedHitCount3, _RedHits3, _, _} = dreyfus_search(TargetDbName,
<<"color:red">>),
{ok, _, GreenHitCount3, _GreenHits3, _, _} = dreyfus_search(TargetDbName,
<<"color:green">>),
?assertEqual(5, RedHitCount3 + GreenHitCount3),
?assertEqual(RedHitCount2, GreenHitCount3),
?assertEqual(GreenHitCount2, RedHitCount3),
delete_db(SourceDbName),
delete_db(TargetDbName),
ok.
test_purge_conflict2() ->
%create dbs and docs
SourceDbName = db_name(),
timer:sleep(2000),
TargetDbName = db_name(),
create_db_docs(SourceDbName),
create_db_docs(TargetDbName, <<"green">>),
%first search
{ok, _, RedHitCount1, _RedHits1, _, _} = dreyfus_search(TargetDbName,
<<"color:red">>),
{ok, _, GreenHitCount1, _GreenHits1, _, _} = dreyfus_search(TargetDbName,
<<"color:green">>),
?assertEqual(5, RedHitCount1 + GreenHitCount1),
%do replicate and make conflicted docs
{ok, _} = fabric:update_doc(<<"_replicator">>, make_replicate_doc(
SourceDbName, TargetDbName), [?ADMIN_CTX]),
wait_for_replicate(TargetDbName, [<<"apple">>, <<"tomato">>, <<"cherry">>,
<<"haw">>, <<"strawberry">>], 2, 5),
%second search
{ok, _, RedHitCount2, _RedHits2, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount2, _GreenHits2, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(5, RedHitCount2 + GreenHitCount2),
purge_docs(TargetDbName, [<<"apple">>, <<"tomato">>, <<"cherry">>,
<<"haw">>, <<"strawberry">>]),
purge_docs(TargetDbName, [<<"apple">>, <<"tomato">>, <<"cherry">>,
<<"haw">>, <<"strawberry">>]),
%third search
{ok, _, RedHitCount3, _RedHits3, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount3, _GreenHits3, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(0, RedHitCount3 + GreenHitCount3),
delete_db(SourceDbName),
delete_db(TargetDbName),
ok.
test_purge_conflict3() ->
%create dbs and docs
SourceDbName = db_name(),
timer:sleep(2000),
TargetDbName = db_name(),
create_db_docs(SourceDbName),
create_db_docs(TargetDbName, <<"green">>),
%first search
{ok, _, RedHitCount1, _RedHits1, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount1, _GreenHits1, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(5, RedHitCount1 + GreenHitCount1),
%do replicate and make conflicted docs
{ok, _} = fabric:update_doc(<<"_replicator">>, make_replicate_doc(
SourceDbName, TargetDbName), [?ADMIN_CTX]),
%%check doc version
wait_for_replicate(TargetDbName, [<<"apple">>, <<"tomato">>, <<"cherry">>,
<<"haw">>, <<"strawberry">>], 2, 5),
%second search
{ok, _, RedHitCount2, _RedHits2, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount2, _GreenHits2, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(5, RedHitCount2 + GreenHitCount2),
purge_docs(TargetDbName, [<<"apple">>, <<"tomato">>, <<"cherry">>,
<<"haw">>, <<"strawberry">>]),
%third search
{ok, _, RedHitCount3, _RedHits3, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount3, _GreenHits3, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(5, RedHitCount3 + GreenHitCount3),
?assertEqual(RedHitCount2, GreenHitCount3),
?assertEqual(GreenHitCount2, RedHitCount3),
purge_docs(TargetDbName, [<<"apple">>, <<"tomato">>, <<"cherry">>,
<<"haw">>, <<"strawberry">>]),
{ok, _, RedHitCount4, _, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount4, _, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(0, RedHitCount4 + GreenHitCount4),
delete_db(SourceDbName),
delete_db(TargetDbName),
ok.
test_purge_conflict4() ->
%create dbs and docs
SourceDbName = db_name(),
timer:sleep(2000),
TargetDbName = db_name(),
create_db_docs(SourceDbName, <<"green">>),
create_db_docs(TargetDbName, <<"red">>),
%first search
{ok, _, RedHitCount1, _RedHits1, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount1, _GreenHits1, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(5, RedHitCount1 + GreenHitCount1),
%do replicate and make conflicted docs
{ok, _} = fabric:update_doc(<<"_replicator">>, make_replicate_doc(
SourceDbName, TargetDbName), [?ADMIN_CTX]),
%%check doc version
wait_for_replicate(TargetDbName, [<<"apple">>, <<"tomato">>, <<"cherry">>,
<<"haw">>, <<"strawberry">>], 2, 5),
%second search
{ok, _, RedHitCount2, _RedHits2, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount2, _GreenHits2, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(5, RedHitCount2 + GreenHitCount2),
purge_docs_with_all_revs(TargetDbName, [<<"apple">>, <<"tomato">>,
<<"cherry">>, <<"haw">>, <<"strawberry">>]),
%third search
{ok, _, RedHitCount3, _RedHits3, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount3, _GreenHits3, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(0, RedHitCount3 + GreenHitCount3),
delete_db(SourceDbName),
delete_db(TargetDbName),
ok.
test_purge_update() ->
%create the db and docs
DbName = db_name(),
create_db_docs(DbName),
QueryRed = <<"color:red">>,
QueryGreen = <<"color:green">>,
%first search request
{ok, _, HitCount1, _, _, _} = dreyfus_search(DbName, QueryRed),
?assertEqual(HitCount1, 5),
%update doc
Rev = get_rev(DbName, <<"apple">>),
Doc = couch_doc:from_json_obj({[
{<<"_id">>, <<"apple">>},
{<<"_rev">>, couch_doc:rev_to_str(Rev)},
{<<"color">>, <<"green">>},
{<<"size">>, 8}
]}),
{ok, _} = fabric:update_docs(DbName, [Doc], [?ADMIN_CTX]),
%second search request
{ok, _, HitCount2, _, _, _} = dreyfus_search(DbName, QueryRed),
{ok, _, HitCount3, _, _, _} = dreyfus_search(DbName, QueryGreen),
% 4 red and 1 green
?assertEqual(HitCount2, 4),
?assertEqual(HitCount3, 1),
% purge 2 docs, 1 red and 1 green
purge_docs(DbName, [<<"apple">>, <<"tomato">>]),
% third search request
{ok, _, HitCount4, _, _, _} = dreyfus_search(DbName, QueryRed),
{ok, _, HitCount5, _, _, _} = dreyfus_search(DbName, QueryGreen),
% 3 red and 0 green
?assertEqual(HitCount4, 3),
?assertEqual(HitCount5, 0),
delete_db(DbName),
ok.
test_purge_update2() ->
%create the db and docs
DbName = db_name(),
create_db_docs(DbName),
Query1 = <<"size:1">>,
Query1000 = <<"size:1000">>,
%first search request
{ok, _, HitCount1, _, _, _} = dreyfus_search(DbName, Query1),
{ok, _, HitCount2, _, _, _} = dreyfus_search(DbName, Query1000),
?assertEqual(HitCount1, 5),
?assertEqual(HitCount2, 0),
%update doc 999 times, it will take about 30 seconds.
update_doc(DbName, <<"apple">>, 999),
%second search request
{ok, _, HitCount3, _, _, _} = dreyfus_search(DbName, Query1),
{ok, _, HitCount4, _, _, _} = dreyfus_search(DbName, Query1000),
% 4 value(1) and 1 value(1000)
?assertEqual(HitCount3, 4),
?assertEqual(HitCount4, 1),
% purge doc
purge_docs(DbName, [<<"apple">>]),
% third search request
{ok, _, HitCount5, _, _, _} = dreyfus_search(DbName, Query1),
{ok, _, HitCount6, _, _, _} = dreyfus_search(DbName, Query1000),
% 4 value(1) and 0 value(1000)
?assertEqual(HitCount5, 4),
?assertEqual(HitCount6, 0),
delete_db(DbName),
ok.
test_delete() ->
DbName = db_name(),
create_db_docs(DbName),
{ok, _, HitCount1, _, _, _} = dreyfus_search(DbName, <<"apple">>),
?assertEqual(HitCount1, 1),
ok = delete_docs(DbName, [<<"apple">>]),
{ok, _, HitCount2, _, _, _} = dreyfus_search(DbName, <<"apple">>),
?assertEqual(HitCount2, 0),
delete_db(DbName),
ok.
test_delete_conflict() ->
%create dbs and docs
SourceDbName = db_name(),
timer:sleep(2000),
TargetDbName = db_name(),
create_db_docs(SourceDbName),
create_db_docs(TargetDbName, <<"green">>),
%first search
{ok, _, RedHitCount1, _RedHits1, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount1, _GreenHits1, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(5, RedHitCount1 + GreenHitCount1),
%do replicate and make conflicted docs
{ok, _} = fabric:update_doc(<<"_replicator">>, make_replicate_doc(
SourceDbName, TargetDbName), [?ADMIN_CTX]),
wait_for_replicate(TargetDbName, [<<"apple">>, <<"tomato">>, <<"cherry">>,
<<"haw">>, <<"strawberry">>], 2, 5),
%second search
{ok, _, RedHitCount2, _RedHits2, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount2, _GreenHits2, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(5, RedHitCount2 + GreenHitCount2),
%delete docs
delete_docs(TargetDbName, [<<"apple">>, <<"tomato">>, <<"cherry">>,
<<"haw">>, <<"strawberry">>]),
%third search
{ok, _, RedHitCount3, _RedHits3, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount3, _GreenHits3, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(5, RedHitCount3 + GreenHitCount3),
?assertEqual(RedHitCount2, GreenHitCount3),
?assertEqual(GreenHitCount2, RedHitCount3),
delete_db(SourceDbName),
delete_db(TargetDbName),
ok.
test_delete_purge_conflict() ->
%create dbs and docs
SourceDbName = db_name(),
timer:sleep(2000),
TargetDbName = db_name(),
create_db_docs(SourceDbName),
create_db_docs(TargetDbName, <<"green">>),
%first search
{ok, _, RedHitCount1, _RedHits1, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount1, _GreenHits1, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(5, RedHitCount1 + GreenHitCount1),
%do replicate and make conflicted docs
{ok, _} = fabric:update_doc(<<"_replicator">>, make_replicate_doc(
SourceDbName, TargetDbName), [?ADMIN_CTX]),
wait_for_replicate(TargetDbName, [<<"apple">>, <<"tomato">>, <<"cherry">>,
<<"haw">>, <<"strawberry">>], 2, 5),
%second search
{ok, _, RedHitCount2, _RedHits2, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount2, _GreenHits2, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(5, RedHitCount2 + GreenHitCount2),
%purge docs
purge_docs(TargetDbName, [<<"apple">>, <<"tomato">>, <<"cherry">>,
<<"haw">>, <<"strawberry">>]),
%delete docs
delete_docs(TargetDbName, [<<"apple">>, <<"tomato">>, <<"cherry">>,
<<"haw">>, <<"strawberry">>]),
%third search
{ok, _, RedHitCount3, _RedHits3, _, _} = dreyfus_search(
TargetDbName, <<"color:red">>),
{ok, _, GreenHitCount3, _GreenHits3, _, _} = dreyfus_search(
TargetDbName, <<"color:green">>),
?assertEqual(RedHitCount3, 0),
?assertEqual(GreenHitCount3, 0),
?assertEqual(GreenHitCount3, 0),
?assertEqual(RedHitCount3, 0),
delete_db(SourceDbName),
delete_db(TargetDbName),
ok.
test_local_doc() ->
DbName = db_name(),
create_db_docs(DbName),
{ok, _, HitCount1, _, _, _} = dreyfus_search(DbName, <<"apple">>),
?assertEqual(HitCount1, 1),
purge_docs(DbName, [<<"apple">>, <<"tomato">>, <<"cherry">>,
<<"strawberry">>]),
{ok, _, HitCount2, _, _, _} = dreyfus_search(DbName, <<"apple">>),
?assertEqual(HitCount2, 0),
%get local doc
[Sig|_] = get_sigs(DbName),
LocalId = dreyfus_util:get_local_purge_doc_id(Sig),
LocalShards = mem3:local_shards(DbName),
PurgeSeqs = lists:map(fun(Shard) ->
{ok, Db} = couch_db:open_int(Shard#shard.name, [?ADMIN_CTX]),
{ok, LDoc} = couch_db:open_doc(Db, LocalId, []),
{Props} = couch_doc:to_json_obj(LDoc, []),
dreyfus_util:get_value_from_options(<<"updated_on">>, Props),
PurgeSeq = dreyfus_util:get_value_from_options(<<"purge_seq">>, Props),
Type = dreyfus_util:get_value_from_options(<<"type">>, Props),
?assertEqual(<<"dreyfus">>, Type),
couch_db:close(Db),
PurgeSeq
end, LocalShards),
?assertEqual(lists:sum(PurgeSeqs), 4),
delete_db(DbName),
ok.
test_verify_index_exists1() ->
DbName = db_name(),
create_db_docs(DbName),
{ok, _, HitCount1, _, _, _} = dreyfus_search(DbName, <<"apple">>),
?assertEqual(HitCount1, 1),
ok = purge_docs(DbName, [<<"apple">>]),
{ok, _, HitCount2, _, _, _} = dreyfus_search(DbName, <<"apple">>),
?assertEqual(HitCount2, 0),
ShardNames = [Sh || #shard{name = Sh} <- mem3:local_shards(DbName)],
[ShardDbName | _Rest ] = ShardNames,
{ok, Db} = couch_db:open(ShardDbName, [?ADMIN_CTX]),
{ok, LDoc} = couch_db:open_doc(Db,
dreyfus_util:get_local_purge_doc_id(
<<"49e82c2a910b1046b55cc45ad058a7ee">>), []
),
#doc{body = {Props}} = LDoc,
?assertEqual(true, dreyfus_util:verify_index_exists(ShardDbName, Props)),
delete_db(DbName),
ok.
test_verify_index_exists2() ->
DbName = db_name(),
create_db_docs(DbName),
{ok, _, HitCount1, _, _, _} = dreyfus_search(DbName, <<"apple">>),
?assertEqual(HitCount1, 1),
ShardNames = [Sh || #shard{name = Sh} <- mem3:local_shards(DbName)],
[ShardDbName | _Rest ] = ShardNames,
{ok, Db} = couch_db:open(ShardDbName, [?ADMIN_CTX]),
{ok, LDoc} = couch_db:open_doc(Db,
dreyfus_util:get_local_purge_doc_id(
<<"49e82c2a910b1046b55cc45ad058a7ee">>), []
),
#doc{body = {Props}} = LDoc,
?assertEqual(true, dreyfus_util:verify_index_exists(ShardDbName, Props)),
delete_db(DbName),
ok.
test_verify_index_exists_failed() ->
DbName = db_name(),
create_db_docs(DbName),
{ok, _, HitCount1, _, _, _} = dreyfus_search(DbName, <<"apple">>),
?assertEqual(HitCount1, 1),
ShardNames = [Sh || #shard{name = Sh} <- mem3:local_shards(DbName)],
[ShardDbName | _Rest ] = ShardNames,
{ok, Db} = couch_db:open(ShardDbName, [?ADMIN_CTX]),
{ok, LDoc} = couch_db:open_doc(Db,
dreyfus_util:get_local_purge_doc_id(
<<"49e82c2a910b1046b55cc45ad058a7ee">>), []
),
#doc{body = {Options}} = LDoc,
OptionsDbErr = [
{<<"indexname">>,
dreyfus_util:get_value_from_options(<<"indexname">>, Options)},
{<<"ddoc_id">>,
dreyfus_util:get_value_from_options(<<"ddoc_id">>, Options)},
{<<"signature">>,
dreyfus_util:get_value_from_options(<<"signature">>, Options)}
],
?assertEqual(false, dreyfus_util:verify_index_exists(
ShardDbName, OptionsDbErr)),
OptionsIdxErr = [
{<<"indexname">>, <<"someindex">>},
{<<"ddoc_id">>,
dreyfus_util:get_value_from_options(<<"ddoc_id">>, Options)},
{<<"signature">>,
dreyfus_util:get_value_from_options(<<"signature">>, Options)}
],
?assertEqual(false, dreyfus_util:verify_index_exists(
ShardDbName, OptionsIdxErr)),
OptionsDDocErr = [
{<<"indexname">>,
dreyfus_util:get_value_from_options(<<"indexname">>, Options)},
{<<"ddoc_id">>,
<<"somedesigndoc">>},
{<<"signature">>,
dreyfus_util:get_value_from_options(<<"signature">>, Options)}
],
?assertEqual(false, dreyfus_util:verify_index_exists(
ShardDbName, OptionsDDocErr)),
OptionsSigErr = [
{<<"indexname">>,
dreyfus_util:get_value_from_options(<<"indexname">>, Options)},
{<<"ddoc_id">>,
dreyfus_util:get_value_from_options(<<"ddoc_id">>, Options)},
{<<"signature">>,
<<"12345678901234567890123456789012">>}
],
?assertEqual(false, dreyfus_util:verify_index_exists(
ShardDbName, OptionsSigErr)),
delete_db(DbName),
ok.
test_delete_local_doc() ->
DbName = db_name(),
create_db_docs(DbName),
{ok, _, HitCount1, _, _, _} = dreyfus_search(DbName, <<"apple">>),
?assertEqual(HitCount1, 1),
ok = purge_docs(DbName, [<<"apple">>]),
{ok, _, HitCount2, _, _, _} = dreyfus_search(DbName, <<"apple">>),
?assertEqual(HitCount2, 0),
LDocId = dreyfus_util:get_local_purge_doc_id(
<<"49e82c2a910b1046b55cc45ad058a7ee">>),
ShardNames = [Sh || #shard{name = Sh} <- mem3:local_shards(DbName)],
[ShardDbName | _Rest ] = ShardNames,
{ok, Db} = couch_db:open(ShardDbName, [?ADMIN_CTX]),
{ok, _} = couch_db:open_doc(Db, LDocId, []),
delete_docs(DbName, [<<"_design/search">>]),
io:format("DbName ~p~n", [DbName]),
?debugFmt("Converting ... ~n~p~n", [DbName]),
dreyfus_fabric_cleanup:go(DbName),
{ok, Db2} = couch_db:open(ShardDbName, [?ADMIN_CTX]),
{not_found, _} = couch_db:open_doc(Db2, LDocId, []),
delete_db(DbName),
ok.
test_purge_search() ->
DbName = db_name(),
create_db_docs(DbName),
purge_docs(DbName, [<<"apple">>, <<"tomato">>, <<"haw">>]),
{ok, _, HitCount, _, _, _} = dreyfus_search(DbName, <<"color:red">>),
?assertEqual(HitCount, 2),
delete_db(DbName),
ok.
%private API
db_name() ->
Nums = tuple_to_list(erlang:now()),
Prefix = "test-db",
Suffix = lists:concat([integer_to_list(Num) || Num <- Nums]),
list_to_binary(Prefix ++ "-" ++ Suffix).
purge_docs(DBName, DocIds) ->
IdsRevs = [{DocId, [get_rev(DBName, DocId)]} || DocId <- DocIds],
{ok, _} = fabric:purge_docs(DBName, IdsRevs, []),
ok.
purge_docs_with_all_revs(DBName, DocIds) ->
IdsRevs = [{DocId, get_revs(DBName, DocId)} || DocId <- DocIds],
{ok, _} = fabric:purge_docs(DBName, IdsRevs, []),
ok.
dreyfus_search(DbName, KeyWord) ->
QueryArgs = #index_query_args{q = KeyWord},
{ok, DDoc} = fabric:open_doc(DbName, <<"_design/search">>, []),
dreyfus_fabric_search:go(DbName, DDoc, <<"index">>, QueryArgs).
create_db_docs(DbName) ->
create_db(DbName),
create_docs(DbName, 5, <<"red">>).
create_db_docs(DbName, Color) ->
create_db(DbName),
create_docs(DbName, 5, Color).
create_docs(DbName, Count, Color) ->
{ok, _} = fabric:update_docs(DbName, make_docs(Count, Color), [?ADMIN_CTX]),
{ok, _} = fabric:update_doc(DbName, make_design_doc(dreyfus), [?ADMIN_CTX]).
create_db(DbName) ->
ok = fabric:create_db(DbName, [?ADMIN_CTX, {q, 1}]).
delete_db(DbName) ->
ok = fabric:delete_db(DbName, [?ADMIN_CTX]).
make_docs(Count, Color) ->
[make_doc(I, Color) || I <- lists:seq(1, Count)].
make_doc(Id, Color) ->
couch_doc:from_json_obj({[
{<<"_id">>, get_value(Id)},
{<<"color">>, Color},
{<<"size">>, 1}
]}).
get_value(Key) ->
case Key of
1 -> <<"apple">>;
2 -> <<"tomato">>;
3 -> <<"cherry">>;
4 -> <<"strawberry">>;
5 -> <<"haw">>;
6 -> <<"carrot">>;
7 -> <<"pitaya">>;
8 -> <<"grape">>;
9 -> <<"date">>;
10 -> <<"watermelon">>
end.
make_design_doc(dreyfus) ->
couch_doc:from_json_obj({[
{<<"_id">>, <<"_design/search">>},
{<<"language">>, <<"javascript">>},
{<<"indexes">>, {[
{<<"index">>, {[
{<<"analyzer">>, <<"standard">>},
{<<"index">>, <<
"function (doc) { \n"
" index(\"default\", doc._id);\n"
" if(doc.color) {\n"
" index(\"color\", doc.color);\n"
" }\n"
" if(doc.size) {\n"
" index(\"size\", doc.size);\n"
" }\n"
"}"
>>}
]}}
]}}
]}).
make_replicate_doc(SourceDbName, TargetDbName) ->
couch_doc:from_json_obj({[
{<<"_id">>, list_to_binary("replicate_fm_" ++
binary_to_list(SourceDbName) ++ "_to_" ++ binary_to_list(TargetDbName))},
{<<"source">>, list_to_binary("http://localhost:15984/" ++ SourceDbName)},
{<<"target">>, list_to_binary("http://localhost:15984/" ++ TargetDbName)}
]}).
get_rev(DbName, DocId) ->
FDI = fabric:get_full_doc_info(DbName, DocId, []),
#doc_info{revs = [#rev_info{} = PrevRev | _]} = couch_doc:to_doc_info(FDI),
PrevRev#rev_info.rev.
get_revs(DbName, DocId) ->
FDI = fabric:get_full_doc_info(DbName, DocId, []),
#doc_info{ revs = Revs } = couch_doc:to_doc_info(FDI),
[Rev#rev_info.rev || Rev <- Revs].
update_doc(_, _, 0) ->
ok;
update_doc(DbName, DocId, Times) ->
Rev = get_rev(DbName, DocId),
Doc = couch_doc:from_json_obj({[
{<<"_id">>, <<"apple">>},
{<<"_rev">>, couch_doc:rev_to_str(Rev)},
{<<"size">>, 1001 - Times}
]}),
{ok, _} = fabric:update_docs(DbName, [Doc], [?ADMIN_CTX]),
update_doc(DbName, DocId, Times-1).
delete_docs(DbName, DocIds) ->
lists:foreach(
fun(DocId) -> ok = delete_doc(DbName, DocId) end,
DocIds
).
delete_doc(DbName, DocId) ->
Rev = get_rev(DbName, DocId),
DDoc = couch_doc:from_json_obj({[
{<<"_id">>, DocId},
{<<"_rev">>, couch_doc:rev_to_str(Rev)},
{<<"_deleted">>, true}
]}),
{ok, _} = fabric:update_doc(DbName, DDoc, [?ADMIN_CTX]),
ok.
wait_for_replicate(_, _, _, 0) ->
couch_log:notice("[~p] wait time out", [?MODULE]),
ok;
wait_for_replicate(DbName, DocIds, ExpectRevCount ,TimeOut)
when is_list(DocIds) ->
[wait_for_replicate(DbName, DocId, ExpectRevCount ,TimeOut) || DocId <- DocIds];
wait_for_replicate(DbName, DocId, ExpectRevCount ,TimeOut) ->
FDI = fabric:get_full_doc_info(DbName, DocId, []),
#doc_info{ revs = Revs } = couch_doc:to_doc_info(FDI),
case erlang:length(Revs) of
ExpectRevCount ->
couch_log:notice("[~p] wait end by expect, time used:~p, DocId:~p",
[?MODULE, 5-TimeOut, DocId]),
ok;
true ->
timer:sleep(1000),
wait_for_replicate(DbName, DocId, ExpectRevCount ,TimeOut-1)
end,
ok.
get_sigs(DbName) ->
{ok, DesignDocs} = fabric:design_docs(DbName),
lists:usort(lists:flatmap(fun active_sigs/1,
[couch_doc:from_json_obj(DD) || DD <- DesignDocs])).
active_sigs(#doc{body={Fields}}=Doc) ->
{RawIndexes} = couch_util:get_value(<<"indexes">>, Fields, {[]}),
{IndexNames, _} = lists:unzip(RawIndexes),
[begin
{ok, Index} = dreyfus_index:design_doc_to_index(Doc, IndexName),
Index#index.sig
end || IndexName <- IndexNames].