blob: 20dcc2f81b66a7eb429f31ddb770b6cb1fb3d29c [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(cpse_test_purge_replication).
-compile(export_all).
-compile(nowarn_export_all).
-include_lib("eunit/include/eunit.hrl").
-include_lib("couch/include/couch_db.hrl").
-include_lib("mem3/include/mem3.hrl").
setup_all() ->
cpse_util:setup_all([mem3, fabric, couch_replicator]).
setup_each() ->
{ok, Src} = cpse_util:create_db(),
{ok, Tgt} = cpse_util:create_db(),
{couch_db:name(Src), couch_db:name(Tgt)}.
teardown_each({SrcDb, TgtDb}) ->
ok = couch_server:delete(SrcDb, []),
ok = couch_server:delete(TgtDb, []).
cpse_purge_http_replication({Source, Target}) ->
{ok, Rev1} = cpse_util:save_doc(Source, {[{'_id', foo}, {vsn, 1}]}),
cpse_util:assert_db_props(?MODULE, ?LINE, Source, [
{doc_count, 1},
{del_doc_count, 0},
{update_seq, 1},
{changes, 1},
{purge_seq, 0},
{purge_infos, []}
]),
RepObject = {[
{<<"source">>, db_url(Source)},
{<<"target">>, db_url(Target)}
]},
{ok, _} = couch_replicator:replicate(RepObject, ?ADMIN_USER),
{ok, Doc1} = cpse_util:open_doc(Target, foo),
cpse_util:assert_db_props(?MODULE, ?LINE, Target, [
{doc_count, 1},
{del_doc_count, 0},
{update_seq, 1},
{changes, 1},
{purge_seq, 0},
{purge_infos, []}
]),
PurgeInfos = [
{cpse_util:uuid(), <<"foo">>, [Rev1]}
],
{ok, [{ok, PRevs}]} = cpse_util:purge(Source, PurgeInfos),
?assertEqual([Rev1], PRevs),
cpse_util:assert_db_props(?MODULE, ?LINE, Source, [
{doc_count, 0},
{del_doc_count, 0},
{update_seq, 2},
{changes, 0},
{purge_seq, 1},
{purge_infos, PurgeInfos}
]),
% Show that a purge on the source is
% not replicated to the target
{ok, _} = couch_replicator:replicate(RepObject, ?ADMIN_USER),
{ok, Doc2} = cpse_util:open_doc(Target, foo),
[Rev2] = Doc2#doc_info.revs,
?assertEqual(Rev1, Rev2#rev_info.rev),
?assertEqual(Doc1, Doc2),
cpse_util:assert_db_props(?MODULE, ?LINE, Target, [
{doc_count, 1},
{del_doc_count, 0},
{update_seq, 1},
{changes, 1},
{purge_seq, 0},
{purge_infos, []}
]),
% Show that replicating from the target
% back to the source reintroduces the doc
RepObject2 = {[
{<<"source">>, db_url(Target)},
{<<"target">>, db_url(Source)}
]},
{ok, _} = couch_replicator:replicate(RepObject2, ?ADMIN_USER),
{ok, Doc3} = cpse_util:open_doc(Source, foo),
[Revs3] = Doc3#doc_info.revs,
?assertEqual(Rev1, Revs3#rev_info.rev),
cpse_util:assert_db_props(?MODULE, ?LINE, Source, [
{doc_count, 1},
{del_doc_count, 0},
{update_seq, 3},
{changes, 1},
{purge_seq, 1},
{purge_infos, PurgeInfos}
]).
cpse_purge_internal_repl_disabled({Source, Target}) ->
cpse_util:with_config([{"mem3", "replicate_purges", "false"}], fun() ->
repl(Source, Target),
{ok, [Rev1, Rev2]} = cpse_util:save_docs(Source, [
{[{'_id', foo1}, {vsn, 1}]},
{[{'_id', foo2}, {vsn, 2}]}
]),
repl(Source, Target),
PurgeInfos1 = [
{cpse_util:uuid(), <<"foo1">>, [Rev1]}
],
{ok, [{ok, PRevs1}]} = cpse_util:purge(Source, PurgeInfos1),
?assertEqual([Rev1], PRevs1),
PurgeInfos2 = [
{cpse_util:uuid(), <<"foo2">>, [Rev2]}
],
{ok, [{ok, PRevs2}]} = cpse_util:purge(Target, PurgeInfos2),
?assertEqual([Rev2], PRevs2),
SrcShard = make_shard(Source),
TgtShard = make_shard(Target),
?assertEqual({ok, 0}, mem3_rep:go(SrcShard, TgtShard)),
?assertEqual({ok, 0}, mem3_rep:go(TgtShard, SrcShard)),
?assertMatch({ok, #doc_info{}}, cpse_util:open_doc(Source, <<"foo2">>)),
?assertMatch({ok, #doc_info{}}, cpse_util:open_doc(Target, <<"foo1">>))
end).
cpse_purge_repl_simple_pull({Source, Target}) ->
repl(Source, Target),
{ok, Rev} = cpse_util:save_doc(Source, {[{'_id', foo}, {vsn, 1}]}),
repl(Source, Target),
PurgeInfos = [
{cpse_util:uuid(), <<"foo">>, [Rev]}
],
{ok, [{ok, PRevs}]} = cpse_util:purge(Target, PurgeInfos),
?assertEqual([Rev], PRevs),
repl(Source, Target).
cpse_purge_repl_simple_push({Source, Target}) ->
repl(Source, Target),
{ok, Rev} = cpse_util:save_doc(Source, {[{'_id', foo}, {vsn, 1}]}),
repl(Source, Target),
PurgeInfos = [
{cpse_util:uuid(), <<"foo">>, [Rev]}
],
{ok, [{ok, PRevs}]} = cpse_util:purge(Source, PurgeInfos),
?assertEqual([Rev], PRevs),
repl(Source, Target).
repl(Source, Target) ->
SrcShard = make_shard(Source),
TgtShard = make_shard(Target),
?assertEqual({ok, 0}, mem3_rep:go(SrcShard, TgtShard)),
SrcTerm = cpse_util:db_as_term(Source, replication),
TgtTerm = cpse_util:db_as_term(Target, replication),
Diff = cpse_util:term_diff(SrcTerm, TgtTerm),
?assertEqual(nodiff, Diff).
make_shard(DbName) ->
#shard{
name = DbName,
node = node(),
dbname = DbName,
range = [0, 16#FFFFFFFF]
}.
db_url(DbName) ->
Addr = config:get("httpd", "bind_address", "127.0.0.1"),
Port = mochiweb_socket_server:get(couch_httpd, port),
Url = ?l2b(io_lib:format("http://~s:~b/~s", [Addr, Port, DbName])),
test_util:wait(fun() ->
case test_request:get(?b2l(Url)) of
{ok, 200, _, _} -> ok;
_ -> wait
end
end),
Url.