summaryrefslogtreecommitdiff
path: root/src/couch_replicator/test/couch_replicator_test_helper.erl
blob: fd040916422f5775254e8c7edfe65f04e279fa99 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
-module(couch_replicator_test_helper).

-include_lib("couch/include/couch_eunit.hrl").
-include_lib("couch/include/couch_db.hrl").
-include_lib("couch_replicator/src/couch_replicator.hrl").

-export([
    compare_dbs/2,
    compare_dbs/3,
    db_url/1,
    replicate/1,
    get_pid/1,
    replicate/2
]).


compare_dbs(Source, Target) ->
    compare_dbs(Source, Target, []).


compare_dbs(Source, Target, ExceptIds) ->
    {ok, SourceDb} = couch_db:open_int(Source, []),
    {ok, TargetDb} = couch_db:open_int(Target, []),

    Fun = fun(FullDocInfo, Acc) ->
        {ok, DocSource} = couch_db:open_doc(SourceDb, FullDocInfo),
        Id = DocSource#doc.id,
        case lists:member(Id, ExceptIds) of
            true ->
                ?assertEqual(not_found, couch_db:get_doc_info(TargetDb, Id));
            false ->
                {ok, TDoc} = couch_db:open_doc(TargetDb, Id),
                compare_docs(DocSource, TDoc)
        end,
        {ok, Acc}
    end,

    {ok, _} = couch_db:fold_docs(SourceDb, Fun, [], []),
    ok = couch_db:close(SourceDb),
    ok = couch_db:close(TargetDb).


compare_docs(Doc1, Doc2) ->
    ?assertEqual(Doc1#doc.body, Doc2#doc.body),
    #doc{atts = Atts1} = Doc1,
    #doc{atts = Atts2} = Doc2,
    ?assertEqual(lists:sort([couch_att:fetch(name, Att) || Att <- Atts1]),
                 lists:sort([couch_att:fetch(name, Att) || Att <- Atts2])),
    FunCompareAtts = fun(Att) ->
        AttName = couch_att:fetch(name, Att),
        {ok, AttTarget} = find_att(Atts2, AttName),
        SourceMd5 = att_md5(Att),
        TargetMd5 = att_md5(AttTarget),
        case AttName of
            <<"att1">> ->
                ?assertEqual(gzip, couch_att:fetch(encoding, Att)),
                ?assertEqual(gzip, couch_att:fetch(encoding, AttTarget)),
                DecSourceMd5 = att_decoded_md5(Att),
                DecTargetMd5 = att_decoded_md5(AttTarget),
                ?assertEqual(DecSourceMd5, DecTargetMd5);
            _ ->
                ?assertEqual(identity, couch_att:fetch(encoding, AttTarget)),
                ?assertEqual(identity, couch_att:fetch(encoding, AttTarget))
        end,
        ?assertEqual(SourceMd5, TargetMd5),
        ?assert(is_integer(couch_att:fetch(disk_len, Att))),
        ?assert(is_integer(couch_att:fetch(att_len, Att))),
        ?assert(is_integer(couch_att:fetch(disk_len, AttTarget))),
        ?assert(is_integer(couch_att:fetch(att_len, AttTarget))),
        ?assertEqual(couch_att:fetch(disk_len, Att),
                     couch_att:fetch(disk_len, AttTarget)),
        ?assertEqual(couch_att:fetch(att_len, Att),
                     couch_att:fetch(att_len, AttTarget)),
        ?assertEqual(couch_att:fetch(type, Att),
                     couch_att:fetch(type, AttTarget)),
        ?assertEqual(couch_att:fetch(md5, Att),
                     couch_att:fetch(md5, AttTarget))
    end,
    lists:foreach(FunCompareAtts, Atts1).


find_att([], _Name) ->
    nil;
find_att([Att | Rest], Name) ->
    case couch_att:fetch(name, Att) of
        Name ->
            {ok, Att};
        _ ->
            find_att(Rest, Name)
    end.


att_md5(Att) ->
    Md50 = couch_att:foldl(
        Att,
        fun(Chunk, Acc) -> couch_hash:md5_hash_update(Acc, Chunk) end,
        couch_hash:md5_hash_init()),
    couch_hash:md5_hash_final(Md50).

att_decoded_md5(Att) ->
    Md50 = couch_att:foldl_decode(
        Att,
        fun(Chunk, Acc) -> couch_hash:md5_hash_update(Acc, Chunk) end,
        couch_hash:md5_hash_init()),
    couch_hash:md5_hash_final(Md50).

db_url(DbName) ->
    iolist_to_binary([
        "http://", config:get("httpd", "bind_address", "127.0.0.1"),
        ":", integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
        "/", DbName
    ]).

get_pid(RepId) ->
    Pid = global:whereis_name({couch_replicator_scheduler_job,RepId}),
    ?assert(is_pid(Pid)),
    Pid.

replicate(Source, Target) ->
    replicate({[
        {<<"source">>, Source},
        {<<"target">>, Target}
    ]}).

replicate({[_ | _]} = RepObject) ->
    {ok, Rep} = couch_replicator_utils:parse_rep_doc(RepObject, ?ADMIN_USER),
    ok = couch_replicator_scheduler:add_job(Rep),
    couch_replicator_scheduler:reschedule(),
    Pid = get_pid(Rep#rep.id),
    MonRef = erlang:monitor(process, Pid),
    receive
        {'DOWN', MonRef, process, Pid, _} ->
            ok
    end,
    ok = couch_replicator_scheduler:remove_job(Rep#rep.id).