summaryrefslogtreecommitdiff
path: root/src/mem3/test/eunit/mem3_shards_test.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem3/test/eunit/mem3_shards_test.erl')
-rw-r--r--src/mem3/test/eunit/mem3_shards_test.erl129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/mem3/test/eunit/mem3_shards_test.erl b/src/mem3/test/eunit/mem3_shards_test.erl
new file mode 100644
index 000000000..9c9bbb402
--- /dev/null
+++ b/src/mem3/test/eunit/mem3_shards_test.erl
@@ -0,0 +1,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(mem3_shards_test).
+
+
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
+-include_lib("mem3/src/mem3_reshard.hrl").
+-include_lib("couch_mrview/include/couch_mrview.hrl"). % for all_docs function
+
+-define(ID, <<"_id">>).
+-define(TIMEOUT, 60).
+
+setup() ->
+ DbName = ?tempdb(),
+ PartProps = [{partitioned, true}, {hash, [couch_partition, hash, []]}],
+ create_db(DbName, [{q, 8}, {n, 1}, {props, PartProps}]),
+ {ok, DbDoc} = mem3_util:open_db_doc(DbName),
+ #{dbname => DbName, dbdoc => DbDoc}.
+
+
+teardown(#{dbname := DbName}) ->
+ delete_db(DbName).
+
+
+start_couch() ->
+ test_util:start_couch(?CONFIG_CHAIN, [mem3, fabric]).
+
+
+stop_couch(Ctx) ->
+ test_util:stop_couch(Ctx).
+
+
+mem3_shards_db_create_props_test_() ->
+ {
+ "mem3 shards partition query database properties tests",
+ {
+ setup,
+ fun start_couch/0, fun stop_couch/1,
+ {
+ foreach,
+ fun setup/0, fun teardown/1,
+ [
+ fun partitioned_shards_recreated_properly/1
+ ]
+ }
+ }
+ }.
+
+
+% This asserts that when the mem3_shards's changes listener on the shards db
+% encounters a db doc update for a db that has a missing shard on the local
+% instance, the shard creation logic will properly propagate the db's config
+% properties.
+% SEE: apache/couchdb#3631
+partitioned_shards_recreated_properly(#{dbname := DbName, dbdoc := DbDoc}) ->
+ {timeout, ?TIMEOUT, ?_test(begin
+ #doc{body = {Body0}} = DbDoc,
+ Body1 = [{<<"foo">>, <<"bar">>} | Body0],
+ Shards = [Shard|_] = lists:sort(mem3:shards(DbName)),
+ ShardName = Shard#shard.name,
+ ?assert(is_partitioned(Shards)),
+ ok = with_proc(fun() -> couch_server:delete(ShardName, []) end),
+ ?assertThrow({not_found, no_db_file}, is_partitioned(Shard)),
+ ok = mem3_util:update_db_doc(DbDoc#doc{body = {Body1}}),
+ Shards = [Shard|_] = test_util:wait_value(fun() ->
+ lists:sort(mem3:shards(DbName))
+ end, Shards),
+ ?assertEqual(true, test_util:wait_value(fun() ->
+ catch is_partitioned(Shard)
+ end, true))
+ end)}.
+
+
+is_partitioned([#shard{}|_]=Shards) ->
+ lists:all(fun is_partitioned/1, Shards);
+is_partitioned(#shard{name=Name}) ->
+ couch_util:with_db(Name, fun couch_db:is_partitioned/1);
+is_partitioned(Db) ->
+ couch_db:is_partitioned(Db).
+
+
+create_db(DbName, Opts) ->
+ GL = erlang:group_leader(),
+ with_proc(fun() -> fabric:create_db(DbName, Opts) end, GL).
+
+
+delete_db(DbName) ->
+ GL = erlang:group_leader(),
+ with_proc(fun() -> fabric:delete_db(DbName, [?ADMIN_CTX]) end, GL).
+
+
+with_proc(Fun) ->
+ with_proc(Fun, undefined, 30000).
+
+
+with_proc(Fun, GroupLeader) ->
+ with_proc(Fun, GroupLeader, 30000).
+
+
+with_proc(Fun, GroupLeader, Timeout) ->
+ {Pid, Ref} = spawn_monitor(fun() ->
+ case GroupLeader of
+ undefined -> ok;
+ _ -> erlang:group_leader(GroupLeader, self())
+ end,
+ exit({with_proc_res, Fun()})
+ end),
+ receive
+ {'DOWN', Ref, process, Pid, {with_proc_res, Res}} ->
+ Res;
+ {'DOWN', Ref, process, Pid, Error} ->
+ error(Error)
+ after Timeout ->
+ erlang:demonitor(Ref, [flush]),
+ exit(Pid, kill),
+ error({with_proc_timeout, Fun, Timeout})
+ end.
+