summaryrefslogtreecommitdiff
path: root/src/couch/test/eunit/couch_bt_engine_compactor_tests.erl
blob: 4c4c43958ebbb69d442ccba1556c6758a2b75b8c (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
% 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_bt_engine_compactor_tests).


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


-define(DELAY, 100).
-define(WAIT_DELAY_COUNT, 50).


setup() ->
    DbName = ?tempdb(),
    {ok, Db} = couch_db:create(DbName, [?ADMIN_CTX]),
    ok = couch_db:close(Db),
    create_docs(DbName),
    DbName.


teardown(DbName) when is_binary(DbName) ->
    couch_server:delete(DbName, [?ADMIN_CTX]),
    ok.


compaction_resume_test_() ->
    {
        setup,
        fun test_util:start_couch/0,
        fun test_util:stop_couch/1,
        {
            foreach,
            fun setup/0,
            fun teardown/1,
            [
                fun compaction_resume/1
            ]
        }
    }.


compaction_resume(DbName) ->
    ?_test(begin
        check_db_validity(DbName),
        compact_db(DbName),
        check_db_validity(DbName),

        % Force an error when copying document ids
        with_mecked_emsort(fun() ->
            compact_db(DbName)
        end),

        check_db_validity(DbName),
        compact_db(DbName),
        check_db_validity(DbName)
    end).


check_db_validity(DbName) ->
    couch_util:with_db(DbName, fun(Db) ->
        ?assertEqual({ok, 3}, couch_db:get_doc_count(Db)),
        ?assertEqual(3, couch_db:count_changes_since(Db, 0))
    end).


with_mecked_emsort(Fun) ->
    meck:new(couch_emsort, [passthrough]),
    meck:expect(couch_emsort, iter, fun(_) -> erlang:error(kaboom) end),
    try
        Fun()
    after
        meck:unload()
    end.


create_docs(DbName) ->
    couch_util:with_db(DbName, fun(Db) ->
        Doc1 = couch_doc:from_json_obj({[
            {<<"_id">>, <<"doc1">>},
            {<<"value">>, 1}

        ]}),
        Doc2 = couch_doc:from_json_obj({[
            {<<"_id">>, <<"doc2">>},
            {<<"value">>, 2}

        ]}),
        Doc3 = couch_doc:from_json_obj({[
            {<<"_id">>, <<"doc3">>},
            {<<"value">>, 3}

        ]}),
        {ok, _} = couch_db:update_docs(Db, [Doc1, Doc2, Doc3])
    end).


compact_db(DbName) ->
    couch_util:with_db(DbName, fun(Db) ->
        {ok, _} = couch_db:start_compact(Db)
    end),
    wait_db_compact_done(DbName, ?WAIT_DELAY_COUNT).


wait_db_compact_done(_DbName, 0) ->
    Failure = [
        {module, ?MODULE},
        {line, ?LINE},
        {reason, "DB compaction failed to finish"}
    ],
    erlang:error({assertion_failed, Failure});
wait_db_compact_done(DbName, N) ->
    IsDone = couch_util:with_db(DbName, fun(Db) ->
        not is_pid(couch_db:get_compactor_pid(Db))
    end),
    if IsDone -> ok; true ->
        timer:sleep(?DELAY),
        wait_db_compact_done(DbName, N - 1)
    end.