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
19
20test_set_name() -> <<"couch_test_partition_versions">>.
21num_set_partitions() -> 4.
22ddoc_id() -> <<"_design/test">>.
23
24main(_) ->
25    test_util:init_code_path(),
26
27    etap:plan(1),
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
37test() ->
38    etap:diag("Testing partition versions de-duplication (MB-19245)"),
39    couch_set_view_test_util:start_server(test_set_name()),
40    create_set(),
41
42    Group1 = get_group(),
43    Header1 = Group1#set_view_group.index_header,
44    PartitionVersions1 = Header1#set_view_index_header.partition_versions,
45
46    % Create a header with duplicated partition versions
47    Header2 = Header1#set_view_index_header{
48        partition_versions = PartitionVersions1 ++ PartitionVersions1
49    },
50    Group2 = Group1#set_view_group{
51        index_header = Header2
52    },
53
54    Group2Dedup = couch_set_view_group:remove_duplicate_partitions(Group2),
55    etap:is(Group2Dedup#set_view_group.index_header, Header1,
56            "Partition versions are correct, rest of header kept unchanged"),
57
58    shutdown_group(),
59    couch_set_view_test_util:stop_server(),
60    ok.
61
62create_set() ->
63    couch_set_view_test_util:delete_set_dbs(test_set_name(),
64        num_set_partitions()),
65    couch_set_view_test_util:create_set_dbs(test_set_name(),
66        num_set_partitions()),
67    couch_set_view:cleanup_index_files(mapreduce_view, test_set_name()),
68    etap:diag("Creating the set databases (# of partitions: " ++
69        integer_to_list(num_set_partitions()) ++ ")"),
70    DDoc = {[
71        {<<"meta">>, {[{<<"id">>, ddoc_id()}]}},
72        {<<"json">>, {[
73            {<<"views">>, {[
74                {<<"test">>, {[
75                    {<<"map">>,
76                        <<"function(doc, meta) {emit(meta.id, doc.value);}">>}
77                ]}}
78            ]}}
79        ]}}
80    ]},
81    ok = couch_set_view_test_util:update_ddoc(test_set_name(), DDoc),
82    etap:diag(io_lib:format(
83        "Configuring set view with partitions [0 .. ~p] as active",
84        [num_set_partitions() div 2 - 1])),
85    etap:diag(io_lib:format(
86        "Configuring set view with partitions [~p .. ~p] as passive",
87        [num_set_partitions() div 2, num_set_partitions() - 1])),
88    Params = #set_view_params{
89        max_partitions = num_set_partitions(),
90        active_partitions = lists:seq(0, num_set_partitions() div 2 - 1),
91        passive_partitions = lists:seq(num_set_partitions() div 2,
92            num_set_partitions() - 1),
93        use_replica_index = false
94    },
95    ok = couch_set_view:define_group(
96        mapreduce_view, test_set_name(), ddoc_id(), Params).
97
98get_group_pid() ->
99    couch_set_view:get_group_pid(
100      mapreduce_view, test_set_name(), ddoc_id(), prod).
101
102get_group() ->
103    GroupPid = get_group_pid(),
104    {ok, Group, 0} = gen_server:call(
105        GroupPid, #set_view_group_req{stale = false, debug = false}, infinity),
106    Group.
107
108shutdown_group() ->
109    couch_dcp_fake_server:reset(),
110    GroupPid = get_group_pid(),
111    couch_set_view_test_util:delete_set_dbs(test_set_name(),
112        num_set_partitions()),
113    MonRef = erlang:monitor(process, GroupPid),
114    receive
115    {'DOWN', MonRef, _, _, _} ->
116        ok
117    after 10000 ->
118        etap:bail("Timeout waiting for group shutdown")
119    end.
120