diff options
Diffstat (limited to '1.1.x/test/etap/112-replication-missing-revs.t')
-rwxr-xr-x | 1.1.x/test/etap/112-replication-missing-revs.t | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/1.1.x/test/etap/112-replication-missing-revs.t b/1.1.x/test/etap/112-replication-missing-revs.t new file mode 100755 index 00000000..39280aee --- /dev/null +++ b/1.1.x/test/etap/112-replication-missing-revs.t @@ -0,0 +1,207 @@ +#!/usr/bin/env escript +%% -*- erlang -*- + +% 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. + +%% XXX: Figure out how to -include("couch_db.hrl") + +-record(doc, {id= <<"">>, revs={0, []}, body={[]}, + attachments=[], deleted=false, meta=[]}). + +-record(http_db, { + url, + auth = [], + resource = "", + headers = [ + {"User-Agent", "CouchDB/"++couch_server:get_version()}, + {"Accept", "application/json"}, + {"Accept-Encoding", "gzip"} + ], + qs = [], + method = get, + body = nil, + options = [ + {response_format,binary}, + {inactivity_timeout, 30000} + ], + retries = 10, + pause = 1, + conn = nil +}). + +main(_) -> + test_util:init_code_path(), + + etap:plan(12), + case (catch test()) of + ok -> + etap:end_tests(); + Other -> + etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), + etap:bail(Other) + end, + ok. + +test() -> + couch_server_sup:start_link(test_util:config_files()), + ibrowse:start(), + crypto:start(), + + couch_server:delete(<<"etap-test-source">>, []), + couch_server:delete(<<"etap-test-target">>, []), + + Dbs1 = setup(), + test_all(local, local), + ok = teardown(Dbs1), + + Dbs2 = setup(), + test_all(local, remote), + ok = teardown(Dbs2), + + Dbs3 = setup(), + test_all(remote, local), + ok = teardown(Dbs3), + + Dbs4 = setup(), + test_all(remote, remote), + ok = teardown(Dbs4), + + ok. + +test_all(SrcType, TgtType) -> + test_unchanged_db(SrcType, TgtType), + test_multiple_changes(SrcType, TgtType), + test_changes_not_missing(SrcType, TgtType). + +test_unchanged_db(SrcType, TgtType) -> + {ok, Pid1} = start_changes_feed(SrcType, 0, false), + {ok, Pid2} = start_missing_revs(TgtType, Pid1), + etap:is( + couch_rep_missing_revs:next(Pid2), + complete, + io_lib:format( + "(~p, ~p) no missing revs if source is unchanged", + [SrcType, TgtType]) + ). + +test_multiple_changes(SrcType, TgtType) -> + Expect = {2, [generate_change(), generate_change()]}, + {ok, Pid1} = start_changes_feed(SrcType, 0, false), + {ok, Pid2} = start_missing_revs(TgtType, Pid1), + etap:is( + get_all_missing_revs(Pid2, {0, []}), + Expect, + io_lib:format("(~p, ~p) add src docs, get missing tgt revs + high seq", + [SrcType, TgtType]) + ). + +test_changes_not_missing(SrcType, TgtType) -> + %% put identical changes on source and target + Id = couch_uuids:random(), + {Id, _Seq, [Rev]} = Expect = generate_change(Id, {[]}, get_db(source)), + {Id, _, [Rev]} = generate_change(Id, {[]}, get_db(target)), + + %% confirm that this change is not in missing revs feed + {ok, Pid1} = start_changes_feed(SrcType, 0, false), + {ok, Pid2} = start_missing_revs(TgtType, Pid1), + {HighSeq, AllRevs} = get_all_missing_revs(Pid2, {0, []}), + + %% etap:none/3 has a bug, so just define it correctly here + etap:is( + lists:member(Expect, AllRevs), + false, + io_lib:format( + "(~p, ~p) skip revs that already exist on target", + [SrcType, TgtType]) + ). + +generate_change() -> + generate_change(couch_uuids:random()). + +generate_change(Id) -> + generate_change(Id, {[]}). + +generate_change(Id, EJson) -> + generate_change(Id, EJson, get_db(source)). + +generate_change(Id, EJson, Db) -> + Doc = couch_doc:from_json_obj(EJson), + Seq = get_update_seq(), + {ok, Rev} = couch_db:update_doc(Db, Doc#doc{id = Id}, [full_commit]), + couch_db:close(Db), + {Id, Seq+1, [Rev]}. + +get_all_missing_revs(Pid, {HighSeq, Revs}) -> + case couch_rep_missing_revs:next(Pid) of + complete -> + {HighSeq, lists:flatten(lists:reverse(Revs))}; + {Seq, More} -> + get_all_missing_revs(Pid, {Seq, [More|Revs]}) + end. + +get_db(source) -> + {ok, Db} = couch_db:open(<<"etap-test-source">>, []), + Db; +get_db(target) -> + {ok, Db} = couch_db:open(<<"etap-test-target">>, []), + Db. + +get_update_seq() -> + Db = get_db(source), + Seq = couch_db:get_update_seq(Db), + couch_db:close(Db), + Seq. + +setup() -> + {ok, DbA} = couch_db:create(<<"etap-test-source">>, []), + {ok, DbB} = couch_db:create(<<"etap-test-target">>, []), + [DbA, DbB]. + +teardown([DbA, DbB]) -> + couch_db:close(DbA), + couch_db:close(DbB), + couch_server:delete(<<"etap-test-source">>, []), + couch_server:delete(<<"etap-test-target">>, []), + ok. + +start_changes_feed(local, Since, Continuous) -> + Props = [{<<"continuous">>, Continuous}], + couch_rep_changes_feed:start_link(self(), get_db(source), Since, Props); +start_changes_feed(remote, Since, Continuous) -> + Props = [{<<"continuous">>, Continuous}], + Db = #http_db{url = server() ++ "etap-test-source/"}, + couch_rep_changes_feed:start_link(self(), Db, Since, Props). + +server() -> + lists:concat([ + "http://127.0.0.1:", mochiweb_socket_server:get(couch_httpd, port), "/" + ]). + +couch_rep_pid(Db) -> + spawn(fun() -> couch_rep_pid_loop(Db) end). + +couch_rep_pid_loop(Db) -> + receive + {'$gen_call', From, get_target_db} -> + gen_server:reply(From, {ok, Db}) + end, + couch_rep_pid_loop(Db). + +start_missing_revs(local, Changes) -> + TargetDb = get_db(target), + MainPid = couch_rep_pid(TargetDb), + couch_rep_missing_revs:start_link(MainPid, TargetDb, Changes, []); +start_missing_revs(remote, Changes) -> + TargetDb = #http_db{url = server() ++ "etap-test-target/"}, + MainPid = couch_rep_pid(TargetDb), + couch_rep_missing_revs:start_link(MainPid, TargetDb, Changes, []). |