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_set_big_reduce">>.
21num_set_partitions() -> 64.
22ddoc_id() -> <<"_design/test">>.
23num_docs() -> 1024.  % keep it a multiple of num_set_partitions()
24
25
26main(_) ->
27    test_util:init_code_path(),
28
29    etap:plan(1),
30    case (catch test()) of
31        ok ->
32            etap:end_tests();
33        Other ->
34            etap:diag(io_lib:format("Test died abnormally: ~p", [Other])),
35            etap:bail(Other)
36    end,
37    ok.
38
39
40test() ->
41    couch_set_view_test_util:start_server(test_set_name()),
42    ReduceValue = setup_test(5000),
43
44    populate_set(1, num_docs()),
45    {ok, {ViewResults}} = couch_set_view_test_util:query_view(
46        test_set_name(), ddoc_id(), <<"testred">>, []),
47    [{<<"rows">>,[{[{<<"key">>,null},{<<"value">>, Result}]}]}] = ViewResults,
48    etap:is(Result, ReduceValue, "Reduce value is correct"),
49
50    shutdown_group(),
51    couch_set_view_test_util:stop_server().
52
53
54setup_test(ReduceSize) ->
55    couch_set_view_test_util:delete_set_dbs(test_set_name(), num_set_partitions()),
56    couch_set_view_test_util:create_set_dbs(test_set_name(), num_set_partitions()),
57
58    ReduceValue = random_binary(ReduceSize),
59    DDoc = {[
60        {<<"meta">>, {[{<<"id">>, ddoc_id()}]}},
61        {<<"json">>, {[
62            {<<"views">>, {[
63                {<<"test">>, {[
64                    {<<"map">>, <<"function(doc, meta) { emit(meta.id, doc.value); }">>}
65                ]}},
66                {<<"testred">>, {[
67                    {<<"map">>, <<"function(doc, meta) { emit(meta.id, doc.value); }">>},
68                    {<<"reduce">>, <<"function() {return \"",
69                        ReduceValue/binary, "\";}">>}
70                ]}}
71            ]}}
72        ]}}
73    ]},
74    ok = couch_set_view_test_util:update_ddoc(test_set_name(), DDoc),
75    ok = configure_view_group(),
76    ReduceValue.
77
78random_binary(N) ->
79    random:seed({1, 2, 3}),
80    << <<(random:uniform(20) + 100):8>> ||  _ <- lists:seq(1, N) >>.
81
82
83shutdown_group() ->
84    GroupPid = couch_set_view:get_group_pid(
85        mapreduce_view, test_set_name(), ddoc_id(), prod),
86    couch_set_view_test_util:delete_set_dbs(test_set_name(), num_set_partitions()),
87    MonRef = erlang:monitor(process, GroupPid),
88    receive
89    {'DOWN', MonRef, _, _, _} ->
90        ok
91    after 10000 ->
92        etap:bail("Timeout waiting for group shutdown")
93    end.
94
95
96populate_set(From, To) ->
97    etap:diag("Populating the " ++ integer_to_list(num_set_partitions()) ++
98        " databases with " ++ integer_to_list(num_docs()) ++ " documents"),
99    DocList = lists:map(
100        fun(I) ->
101            Doc = iolist_to_binary(["doc", integer_to_list(I)]),
102            {[
103                {<<"meta">>, {[{<<"id">>, Doc}]}},
104                {<<"json">>, {[{<<"value">>, I}]}}
105            ]}
106        end,
107        lists:seq(From, To)),
108    ok = couch_set_view_test_util:populate_set_sequentially(
109        test_set_name(),
110        lists:seq(0, num_set_partitions() - 1),
111        DocList).
112
113
114configure_view_group() ->
115    etap:diag("Configuring view group"),
116    Params = #set_view_params{
117        max_partitions = num_set_partitions(),
118        active_partitions = lists:seq(0, num_set_partitions()-1),
119        passive_partitions = [],
120        use_replica_index = false
121    },
122    try
123        couch_set_view:define_group(
124            mapreduce_view, test_set_name(), ddoc_id(), Params)
125    catch _:Error ->
126        Error
127    end.
128