1#!/usr/bin/env escript
2%% -*- Mode: Erlang; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3%%! -smp enable
4
5% Licensed under the Apache License, Version 2.0 (the "License"); you may not
6% use this file except in compliance with the License. You may obtain a copy of
7% the License at
8%
9%   http://www.apache.org/licenses/LICENSE-2.0
10%
11% Unless required by applicable law or agreed to in writing, software
12% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14% License for the specific language governing permissions and limitations under
15% the License.
16
17-include_lib("couch_set_view/include/couch_set_view.hrl").
18
19test_set_name() -> <<"couch_test_set_index_replica_index_missing">>.
20num_set_partitions() -> 64.
21ddoc_id() -> <<"_design/test">>.
22
23
24main(_) ->
25    test_util:init_code_path(),
26
27    etap:plan(13),
28    case (catch test()) of
29        ok ->
30            etap:end_tests();
31        Other ->
32            etap:diag(io_lib:format("Test died abnormally: ~p", [Other])),
33            etap:bail(Other)
34    end,
35    ok.
36
37
38test() ->
39    couch_set_view_test_util:start_server(test_set_name()),
40
41    couch_set_view_test_util:delete_set_dbs(test_set_name(), num_set_partitions()),
42    couch_set_view_test_util:create_set_dbs(test_set_name(), num_set_partitions()),
43
44    configure_group(),
45
46    MainPid = get_main_pid(),
47    etap:is(true, is_process_alive(MainPid), "Main group is alive"),
48    etap:is(true, couch_set_view_group:is_view_defined(MainPid), "Main group is configured"),
49
50    RepPid = get_replica_pid(MainPid),
51    etap:is(true, is_process_alive(RepPid), "Replica group is alive"),
52    etap:is(true, couch_set_view_group:is_view_defined(RepPid), "Replica group is configured"),
53
54    RepIndexFile = replica_index_file(),
55    etap:is(true, filelib:is_file(RepIndexFile), "Replica index file found"),
56
57    etap:diag("Shutting down view group"),
58    couch_util:shutdown_sync(MainPid),
59
60    etap:is(true, filelib:is_file(RepIndexFile), "Replica index file not deleted"),
61    etap:diag("Deleting index file"),
62    ok = file:delete(RepIndexFile),
63    etap:is(false, filelib:is_file(RepIndexFile), "Replica index file deleted"),
64
65    wait_group_shutdown(MainPid),
66
67    etap:diag("Opening view groups again"),
68    MainPid2 = get_main_pid(),
69    etap:is(true, is_process_alive(MainPid2), "Main group is alive"),
70    etap:is(true, couch_set_view_group:is_view_defined(MainPid2), "Main group is configured"),
71    RepPid2 = get_replica_pid(MainPid2),
72    etap:is(true, is_process_alive(RepPid2), "Replica group is alive"),
73    etap:is(true, couch_set_view_group:is_view_defined(RepPid2), "Replica group is configured"),
74
75    {ok, MainGroup} = gen_server:call(MainPid2, request_group, infinity),
76    {ok, RepGroup} = gen_server:call(RepPid2, request_group, infinity),
77
78    etap:is(?set_num_partitions(RepGroup),
79            ?set_num_partitions(MainGroup),
80            "Replica group has same number of max partitions as main group"),
81
82    etap:is(true, filelib:is_file(RepIndexFile), "Replica index file recreated"),
83
84    couch_set_view_test_util:delete_set_dbs(test_set_name(), num_set_partitions()),
85    couch_set_view_test_util:stop_server(),
86    ok.
87
88
89configure_group() ->
90    couch_set_view:cleanup_index_files(mapreduce_view, test_set_name()),
91    DDoc = {[
92        {<<"meta">>, {[{<<"id">>, ddoc_id()}]}},
93        {<<"json">>, {[
94        {<<"views">>, {[
95            {<<"view_1">>, {[
96                {<<"map">>, <<"function(doc, meta) { emit(meta.id, doc.value); }">>},
97                {<<"reduce">>, <<"_count">>}
98            ]}}
99        ]}}
100        ]}}
101    ]},
102    ok = couch_set_view_test_util:update_ddoc(test_set_name(), DDoc),
103    etap:diag("Configuring set view with partitions [0 .. 31] as active"),
104    Params = #set_view_params{
105        max_partitions = num_set_partitions(),
106        active_partitions = lists:seq(0, 31),
107        passive_partitions = [],
108        use_replica_index = true
109    },
110    ok = couch_set_view:define_group(
111        mapreduce_view, test_set_name(), ddoc_id(), Params).
112
113
114get_main_pid() ->
115    couch_set_view:get_group_pid(
116        mapreduce_view, test_set_name(), ddoc_id(), prod).
117
118
119get_replica_pid(MainPid) ->
120    {ok, Group} = gen_server:call(MainPid, request_group, infinity),
121    Group#set_view_group.replica_pid.
122
123
124replica_index_file() ->
125    RootDir = couch_config:get("couchdb", "view_index_dir"),
126    IndexDir = couch_set_view:set_index_dir(RootDir, test_set_name(), prod),
127    {ok, GroupSig} = couch_set_view:get_group_signature(
128        mapreduce_view, test_set_name(), ddoc_id()),
129    filename:join([IndexDir, "replica_" ++ binary_to_list(GroupSig) ++ ".view.1"]).
130
131
132wait_group_shutdown(OldPid) ->
133    NewPid = get_main_pid(),
134    case NewPid of
135    OldPid ->
136        ok = timer:sleep(50),
137        wait_group_shutdown(OldPid);
138    _ ->
139        ok
140    end.
141