Github user kxepal commented on a diff in the pull request:

    https://github.com/apache/couchdb/pull/253#discussion_r14903362
  
    --- Diff: src/couch_replicator/test/couch_replicator_compact_tests.erl ---
    @@ -0,0 +1,448 @@
    +% 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_replicator_compact_tests).
    +
    +-include("couch_eunit.hrl").
    +-include_lib("couchdb/couch_db.hrl").
    +-include_lib("couch_replicator/src/couch_replicator.hrl").
    +
    +-define(ADMIN_ROLE, #user_ctx{roles=[<<"_admin">>]}).
    +-define(ADMIN_USER, {user_ctx, ?ADMIN_ROLE}).
    +-define(ATTFILE, filename:join([?FIXTURESDIR, "logo.png"])).
    +-define(DELAY, 100).
    +-define(TIMEOUT, 30000).
    +-define(TIMEOUT_STOP, 1000).
    +-define(TIMEOUT_WRITER, 3000).
    +-define(TIMEOUT_EUNIT, ?TIMEOUT div 1000 + 5).
    +
    +setup() ->
    +    DbName = ?tempdb(),
    +    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
    +    ok = couch_db:close(Db),
    +    DbName.
    +
    +setup(local) ->
    +    setup();
    +setup(remote) ->
    +    {remote, setup()};
    +setup({A, B}) ->
    +    {ok, _} = couch_server_sup:start_link(?CONFIG_CHAIN),
    +    Source = setup(A),
    +    Target = setup(B),
    +    {Source, Target}.
    +
    +teardown({remote, DbName}) ->
    +    teardown(DbName);
    +teardown(DbName) ->
    +    ok = couch_server:delete(DbName, [?ADMIN_USER]),
    +    ok.
    +
    +teardown(_, {Source, Target}) ->
    +    teardown(Source),
    +    teardown(Target),
    +
    +    Pid = whereis(couch_server_sup),
    +    erlang:monitor(process, Pid),
    +    couch_server_sup:stop(),
    +    receive
    +        {'DOWN', _, _, Pid, _} ->
    +            ok
    +    after ?TIMEOUT_STOP ->
    +        throw({timeout, server_stop})
    +    end.
    +
    +
    +compact_test_() ->
    +    Pairs = [{local, local}, {local, remote},
    +             {remote, local}, {remote, remote}],
    +    {
    +        "Compaction during replication tests",
    +        {
    +            foreachx,
    +            fun setup/1, fun teardown/2,
    +            [{Pair, fun should_populate_replicate_compact/2}
    +             || Pair <- Pairs]
    +        }
    +    }.
    +
    +
    +should_populate_replicate_compact({From, To}, {Source, Target}) ->
    +    {ok, RepPid, RepId} = replicate(Source, Target),
    +    {lists:flatten(io_lib:format("~p -> ~p", [From, To])),
    +     {inorder, [
    +         should_run_replication(RepPid, RepId, Source, Target),
    +         should_all_processes_be_alive(RepPid, Source, Target),
    +         should_populate_and_compact(RepPid, Source, Target, 50, 5),
    +         should_wait_target_in_sync(Source, Target),
    +         should_ensure_replication_still_running(RepPid, RepId, Source, 
Target),
    +         should_cancel_replication(RepId, RepPid),
    +         should_compare_databases(Source, Target)
    +     ]}}.
    +
    +should_all_processes_be_alive(RepPid, Source, Target) ->
    +    ?_test(begin
    +        {ok, SourceDb} = reopen_db(Source),
    +        {ok, TargetDb} = reopen_db(Target),
    +        ?assert(is_process_alive(RepPid)),
    +        ?assert(is_process_alive(SourceDb#db.main_pid)),
    +        ?assert(is_process_alive(TargetDb#db.main_pid))
    +    end).
    +
    +should_run_replication(RepPid, RepId, Source, Target) ->
    +    ?_test(check_active_tasks(RepPid, RepId, Source, Target)).
    +
    +should_ensure_replication_still_running(RepPid, RepId, Source, Target) ->
    +    ?_test(check_active_tasks(RepPid, RepId, Source, Target)).
    +
    +check_active_tasks(RepPid, {BaseId, Ext} = _RepId, Src, Tgt) ->
    +    Source = case Src of
    +        {remote, NameSrc} ->
    +            <<(db_url(NameSrc))/binary, $/>>;
    +        _ ->
    +            Src
    +    end,
    +    Target = case Tgt of
    +        {remote, NameTgt} ->
    +            <<(db_url(NameTgt))/binary, $/>>;
    +        _ ->
    +            Tgt
    +    end,
    +    FullRepId = ?l2b(BaseId ++ Ext),
    +    Pid = ?l2b(pid_to_list(RepPid)),
    +    [RepTask] = couch_task_status:all(),
    +    ?assertEqual(Pid, couch_util:get_value(pid, RepTask)),
    +    ?assertEqual(FullRepId, couch_util:get_value(replication_id, RepTask)),
    +    ?assertEqual(true, couch_util:get_value(continuous, RepTask)),
    +    ?assertEqual(Source, couch_util:get_value(source, RepTask)),
    +    ?assertEqual(Target, couch_util:get_value(target, RepTask)),
    +    ?assert(is_integer(couch_util:get_value(docs_read, RepTask))),
    +    ?assert(is_integer(couch_util:get_value(docs_written, RepTask))),
    +    ?assert(is_integer(couch_util:get_value(doc_write_failures, RepTask))),
    +    ?assert(is_integer(couch_util:get_value(revisions_checked, RepTask))),
    +    ?assert(is_integer(couch_util:get_value(missing_revisions_found, 
RepTask))),
    +    ?assert(is_integer(couch_util:get_value(checkpointed_source_seq, 
RepTask))),
    +    ?assert(is_integer(couch_util:get_value(source_seq, RepTask))),
    +    Progress = couch_util:get_value(progress, RepTask),
    +    ?assert(is_integer(Progress)),
    +    ?assert(Progress =< 100).
    +
    +should_cancel_replication(RepId, RepPid) ->
    +    ?_assertNot(begin
    +        {ok, _} = couch_replicator:cancel_replication(RepId),
    +        is_process_alive(RepPid)
    +    end).
    +
    +should_populate_and_compact(RepPid, Source, Target, BatchSize, Rounds) ->
    +    {timeout, ?TIMEOUT_EUNIT, ?_test(begin
    +        {ok, SourceDb0} = reopen_db(Source),
    +        Writer = spawn_writer(SourceDb0),
    +        lists:foreach(
    +            fun(N) ->
    +                {ok, SourceDb} = reopen_db(Source),
    +                {ok, TargetDb} = reopen_db(Target),
    +                pause_writer(Writer),
    +
    +                compact_db("source", SourceDb),
    +                ?assert(is_process_alive(RepPid)),
    +                ?assert(is_process_alive(SourceDb#db.main_pid)),
    +                check_ref_counter("source", SourceDb),
    +
    +                compact_db("target", TargetDb),
    +                ?assert(is_process_alive(RepPid)),
    +                ?assert(is_process_alive(TargetDb#db.main_pid)),
    +                check_ref_counter("target", TargetDb),
    +
    +                {ok, SourceDb2} = reopen_db(SourceDb),
    +                {ok, TargetDb2} = reopen_db(TargetDb),
    +
    +                resume_writer(Writer),
    +                wait_writer(Writer, BatchSize * N),
    +
    +                compact_db("source", SourceDb2),
    +                ?assert(is_process_alive(RepPid)),
    +                ?assert(is_process_alive(SourceDb2#db.main_pid)),
    +                pause_writer(Writer),
    +                check_ref_counter("source", SourceDb2),
    +                resume_writer(Writer),
    +
    +                compact_db("target", TargetDb2),
    +                ?assert(is_process_alive(RepPid)),
    +                ?assert(is_process_alive(TargetDb2#db.main_pid)),
    +                pause_writer(Writer),
    +                check_ref_counter("target", TargetDb2),
    +                resume_writer(Writer)
    +            end, lists:seq(1, Rounds)),
    +        stop_writer(Writer)
    +    end)}.
    +
    +should_wait_target_in_sync({remote, Source}, Target) ->
    +    should_wait_target_in_sync(Source, Target);
    +should_wait_target_in_sync(Source, {remote, Target}) ->
    +    should_wait_target_in_sync(Source, Target);
    +should_wait_target_in_sync(Source, Target) ->
    +    {timeout, ?TIMEOUT_EUNIT, ?_assert(begin
    +        {ok, SourceDb} = couch_db:open_int(Source, []),
    +        {ok, SourceInfo} = couch_db:get_db_info(SourceDb),
    +        ok = couch_db:close(SourceDb),
    +        SourceDocCount = couch_util:get_value(doc_count, SourceInfo),
    +        wait_target_in_sync_loop(SourceDocCount, Target, 300)
    +    end)}.
    +
    +wait_target_in_sync_loop(_DocCount, _TargetName, 0) ->
    +    erlang:error(
    +        {assertion_failed,
    +         [{module, ?MODULE}, {line, ?LINE},
    +          {reason, "Could not get source and target databases in sync"}]});
    +wait_target_in_sync_loop(DocCount, {remote, TargetName}, RetriesLeft) ->
    +    wait_target_in_sync_loop(DocCount, TargetName, RetriesLeft);
    +wait_target_in_sync_loop(DocCount, TargetName, RetriesLeft) ->
    +    {ok, Target} = couch_db:open_int(TargetName, []),
    +    {ok, TargetInfo} = couch_db:get_db_info(Target),
    +    ok = couch_db:close(Target),
    +    TargetDocCount = couch_util:get_value(doc_count, TargetInfo),
    +    case TargetDocCount == DocCount of
    +        true ->
    +            true;
    +        false ->
    +            ok = timer:sleep(?DELAY),
    +            wait_target_in_sync_loop(DocCount, TargetName, RetriesLeft - 1)
    +    end.
    +
    +should_compare_databases({remote, Source}, Target) ->
    +    should_compare_databases(Source, Target);
    +should_compare_databases(Source, {remote, Target}) ->
    +    should_compare_databases(Source, Target);
    +should_compare_databases(Source, Target) ->
    +    {timeout, 35, ?_test(begin
    +        {ok, SourceDb} = couch_db:open_int(Source, []),
    +        {ok, TargetDb} = couch_db:open_int(Target, []),
    +        Fun = fun(FullDocInfo, _, Acc) ->
    +            {ok, Doc} = couch_db:open_doc(SourceDb, FullDocInfo),
    +            {Props} = DocJson = couch_doc:to_json_obj(Doc, [attachments]),
    +            DocId = couch_util:get_value(<<"_id">>, Props),
    +            DocTarget = case couch_db:open_doc(TargetDb, DocId) of
    +                {ok, DocT} ->
    +                    DocT;
    +                Error ->
    +                    erlang:error(
    --- End diff --
    
    to simulate assertion fail in the way that eunit does. suddenly, it has no 
any `?_fail` macro for that case.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at [email protected] or file a JIRA ticket
with INFRA.
---

Reply via email to