summaryrefslogtreecommitdiff
path: root/src/couch_peruser/test/eunit/couch_peruser_test.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/couch_peruser/test/eunit/couch_peruser_test.erl')
-rw-r--r--src/couch_peruser/test/eunit/couch_peruser_test.erl519
1 files changed, 519 insertions, 0 deletions
diff --git a/src/couch_peruser/test/eunit/couch_peruser_test.erl b/src/couch_peruser/test/eunit/couch_peruser_test.erl
new file mode 100644
index 000000000..8501cc36f
--- /dev/null
+++ b/src/couch_peruser/test/eunit/couch_peruser_test.erl
@@ -0,0 +1,519 @@
+% 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_peruser_test).
+
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
+
+-define(ADMIN_USERNAME, "admin").
+-define(ADMIN_PASSWORD, "secret").
+
+-define(WAIT_FOR_USER_DELETE_TIMEOUT, 3000).
+
+setup_all() ->
+ TestCtx = test_util:start_couch([chttpd]),
+ ok = application:start(couch_peruser),
+ Hashed = couch_passwords:hash_admin_password(?ADMIN_PASSWORD),
+ ok = config:set("admins", ?ADMIN_USERNAME, ?b2l(Hashed), _Persist=false),
+ TestCtx.
+
+teardown_all(TestCtx) ->
+ config:delete("admins", ?ADMIN_USERNAME),
+ ok = application:stop(couch_peruser),
+ test_util:stop_couch(TestCtx).
+
+setup() ->
+ TestAuthDb = ?tempdb(),
+ do_request(put, get_base_url() ++ "/" ++ ?b2l(TestAuthDb)),
+ do_request(put, get_cluster_base_url() ++ "/" ++ ?b2l(TestAuthDb)),
+ set_config("couch_httpd_auth", "authentication_db", ?b2l(TestAuthDb)),
+ set_config("couch_peruser", "cluster_quiet_period", "1"),
+ set_config("couch_peruser", "cluster_start_period", "1"),
+ set_config("couch_peruser", "enable", "true"),
+ set_config("cluster", "n", "1"),
+ TestAuthDb.
+
+teardown(TestAuthDb) ->
+ set_config("couch_peruser", "enable", "false"),
+ set_config("couch_peruser", "delete_dbs", "false"),
+ set_config("couch_httpd_auth", "authentication_db", "_users"),
+ set_config("couch_peruser", "cluster_quiet_period", "60"),
+ set_config("couch_peruser", "cluster_start_period", "5"),
+ set_config("cluster", "n", "3"),
+ do_request(delete, get_cluster_base_url() ++ "/" ++ ?b2l(TestAuthDb)),
+ do_request(delete, get_base_url() ++ "/" ++ ?b2l(TestAuthDb)),
+ lists:foreach(fun(DbName) ->
+ case binary:part(DbName, 0, 7) of
+ <<"userdb-">> -> delete_db(DbName);
+ _ -> ok
+ end
+ end, all_dbs()).
+
+set_config(Section, Key, Value) ->
+ ok = config:set(Section, Key, Value, _Persist=false).
+
+delete_config(Section, Key) ->
+ ok = config:delete(Section, Key, _Persist=false).
+
+do_request(Method, Url) ->
+ Headers = [{basic_auth, {?ADMIN_USERNAME, ?ADMIN_PASSWORD}}],
+ {ok, _, _, _} = test_request:request(Method, Url, Headers).
+
+do_request(Method, Url, Body) ->
+ Headers = [
+ {basic_auth, {?ADMIN_USERNAME, ?ADMIN_PASSWORD}},
+ {"Content-Type", "application/json"}],
+ {ok, _, _, _} = test_request:request(Method, Url, Headers, Body).
+
+do_anon_request(Method, Url, Body) ->
+ Headers = [
+ {"Content-Type", "application/json"}],
+ {ok, _, _, _} = test_request:request(Method, Url, Headers, Body).
+
+create_db(DbName) ->
+ {ok, _, _, _} = do_request(put, get_cluster_base_url() ++ "/" ++ ?b2l(DbName)).
+
+delete_db(DbName) ->
+ {ok, _, _, _} = do_request(delete, get_cluster_base_url() ++ "/" ++ ?b2l(DbName)).
+
+create_user(AuthDb, Name) ->
+ Body = "{\"name\":\"" ++ Name ++
+ "\",\"type\":\"user\",\"roles\":[],\"password\":\"secret\"}",
+ Url = lists:concat([
+ get_cluster_base_url(), "/", ?b2l(AuthDb), "/org.couchdb.user:", Name]),
+ {ok, 201, _, _} = do_request(put, Url, Body).
+
+create_anon_user(AuthDb, Name) ->
+ Body = "{\"name\":\"" ++ Name ++
+ "\",\"type\":\"user\",\"roles\":[],\"password\":\"secret\"}",
+ Url = lists:concat([
+ get_cluster_base_url(), "/", ?b2l(AuthDb), "/org.couchdb.user:", Name]),
+ {ok, 201, _, _} = do_anon_request(put, Url, Body).
+
+delete_user(AuthDb, Name) ->
+ Url = lists:concat([get_cluster_base_url(), "/", ?b2l(AuthDb),
+ "/org.couchdb.user:", Name]),
+ {ok, 200, _, Body} = do_request(get, Url),
+ {DocProps} = jiffy:decode(Body),
+ Rev = proplists:get_value(<<"_rev">>, DocProps),
+ {ok, 200, _, _} = do_request(delete, Url ++ "?rev=" ++ ?b2l(Rev)).
+
+get_security(DbName) ->
+ Url = lists:concat([
+ get_cluster_base_url(), "/", ?b2l(DbName), "/_security"]),
+ test_util:wait(fun() ->
+ {ok, 200, _, Body} = do_request(get, Url),
+ case jiffy:decode(Body) of
+ {[]} -> wait;
+ {SecurityProperties} -> SecurityProperties
+ end
+ end).
+
+set_security(DbName, SecurityProperties) ->
+ Url = lists:concat([
+ get_cluster_base_url(), "/", ?b2l(DbName), "/_security"]),
+ Body = jiffy:encode({SecurityProperties}),
+ {ok, 200, _, _} = do_request(put, Url, Body).
+
+all_dbs() ->
+ {ok, 200, _, Body} = do_request(get, get_cluster_base_url() ++ "/_all_dbs"),
+ jiffy:decode(Body).
+
+all_dbs_with_errors() ->
+ {Result, StatusCode, _Headers, Body} = do_request(get, get_cluster_base_url() ++ "/_all_dbs"),
+ {Result, StatusCode, _Headers, jiffy:decode(Body)}.
+
+get_base_url() ->
+ Addr = config:get("httpd", "bind_address", "127.0.0.1"),
+ Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+ "http://" ++ Addr ++ ":" ++ Port.
+
+get_cluster_base_url() ->
+ Addr = config:get("httpd", "bind_address", "127.0.0.1"),
+ Port = integer_to_list(mochiweb_socket_server:get(chttpd, port)),
+ "http://" ++ Addr ++ ":" ++ Port.
+
+
+should_create_user_db_with_default(TestAuthDb) ->
+ create_user(TestAuthDb, "foo"),
+ wait_for_db_create(<<"userdb-666f6f">>),
+ {ok, DbInfo} = fabric:get_db_info(<<"userdb-666f6f">>),
+ {ClusterInfo} = couch_util:get_value(cluster, DbInfo),
+ [
+ ?_assert(lists:member(<<"userdb-666f6f">>, all_dbs())),
+ ?_assertEqual(1, couch_util:get_value(q, ClusterInfo))
+ ].
+
+should_create_user_db_with_custom_prefix(TestAuthDb) ->
+ set_config("couch_peruser", "database_prefix", "newuserdb-"),
+ create_user(TestAuthDb, "fooo"),
+ wait_for_db_create(<<"newuserdb-666f6f6f">>),
+ delete_config("couch_peruser", "database_prefix"),
+ ?_assert(lists:member(<<"newuserdb-666f6f6f">>, all_dbs())).
+
+should_create_user_db_with_custom_special_prefix(TestAuthDb) ->
+ set_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+ create_user(TestAuthDb, "fooo"),
+ wait_for_db_create(<<"userdb_$()+--/666f6f6f">>),
+ delete_config("couch_peruser", "database_prefix"),
+ ?_assert(lists:member(<<"userdb_$()+--/666f6f6f">>, all_dbs())).
+
+should_create_anon_user_db_with_default(TestAuthDb) ->
+ create_anon_user(TestAuthDb, "fooo"),
+ wait_for_db_create(<<"userdb-666f6f6f">>),
+ {ok, DbInfo} = fabric:get_db_info(<<"userdb-666f6f6f">>),
+ {ClusterInfo} = couch_util:get_value(cluster, DbInfo),
+ [
+ ?_assert(lists:member(<<"userdb-666f6f6f">>, all_dbs())),
+ ?_assertEqual(1, couch_util:get_value(q, ClusterInfo))
+ ].
+
+should_create_anon_user_db_with_custom_prefix(TestAuthDb) ->
+ set_config("couch_peruser", "database_prefix", "newuserdb-"),
+ create_anon_user(TestAuthDb, "fooo"),
+ wait_for_db_create(<<"newuserdb-666f6f6f">>),
+ delete_config("couch_peruser", "database_prefix"),
+ ?_assert(lists:member(<<"newuserdb-666f6f6f">>, all_dbs())).
+
+should_create_anon_user_db_with_custom_special_prefix(TestAuthDb) ->
+ set_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+ create_anon_user(TestAuthDb, "fooo"),
+ wait_for_db_create(<<"userdb_$()+--/666f6f6f">>),
+ delete_config("couch_peruser", "database_prefix"),
+ ?_assert(lists:member(<<"userdb_$()+--/666f6f6f">>, all_dbs())).
+
+should_create_user_db_with_q4(TestAuthDb) ->
+ set_config("couch_peruser", "q", "4"),
+ create_user(TestAuthDb, "foo"),
+ wait_for_db_create(<<"userdb-666f6f">>),
+ {ok, DbInfo} = fabric:get_db_info(<<"userdb-666f6f">>),
+ {ClusterInfo} = couch_util:get_value(cluster, DbInfo),
+ delete_config("couch_peruser", "q"),
+ [
+ ?_assert(lists:member(<<"userdb-666f6f">>, all_dbs())),
+ ?_assertEqual(4, couch_util:get_value(q, ClusterInfo))
+ ].
+
+should_create_anon_user_db_with_q4(TestAuthDb) ->
+ set_config("couch_peruser", "q", "4"),
+ create_anon_user(TestAuthDb, "fooo"),
+ wait_for_db_create(<<"userdb-666f6f6f">>),
+ {ok, TargetInfo} = fabric:get_db_info(<<"userdb-666f6f6f">>),
+ {ClusterInfo} = couch_util:get_value(cluster, TargetInfo),
+ delete_config("couch_peruser", "q"),
+ [
+ ?_assert(lists:member(<<"userdb-666f6f6f">>, all_dbs())),
+ ?_assertEqual(4, couch_util:get_value(q, ClusterInfo))
+ ].
+
+should_not_delete_user_db(TestAuthDb) ->
+ User = "foo",
+ UserDbName = <<"userdb-666f6f">>,
+ create_user(TestAuthDb, User),
+ wait_for_db_create(<<"userdb-666f6f">>),
+ AfterCreate = lists:member(UserDbName, all_dbs()),
+ delete_user(TestAuthDb, User),
+ timer:sleep(?WAIT_FOR_USER_DELETE_TIMEOUT),
+ AfterDelete = lists:member(UserDbName, all_dbs()),
+ [?_assert(AfterCreate), ?_assert(AfterDelete)].
+
+should_delete_user_db(TestAuthDb) ->
+ User = "bar",
+ UserDbName = <<"userdb-626172">>,
+ set_config("couch_peruser", "delete_dbs", "true"),
+ create_user(TestAuthDb, User),
+ wait_for_db_create(UserDbName),
+ AfterCreate = lists:member(UserDbName, all_dbs()),
+ delete_user(TestAuthDb, User),
+ wait_for_db_delete(UserDbName),
+ AfterDelete = lists:member(UserDbName, all_dbs()),
+ [?_assert(AfterCreate), ?_assertNot(AfterDelete)].
+
+should_delete_user_db_with_custom_prefix(TestAuthDb) ->
+ User = "bar",
+ UserDbName = <<"newuserdb-626172">>,
+ set_config("couch_peruser", "delete_dbs", "true"),
+ set_config("couch_peruser", "database_prefix", "newuserdb-"),
+ create_user(TestAuthDb, User),
+ wait_for_db_create(UserDbName),
+ AfterCreate = lists:member(UserDbName, all_dbs()),
+ delete_user(TestAuthDb, User),
+ wait_for_db_delete(UserDbName),
+ delete_config("couch_peruser", "database_prefix"),
+ AfterDelete = lists:member(UserDbName, all_dbs()),
+ [
+ ?_assert(AfterCreate),
+ ?_assertNot(AfterDelete)
+ ].
+
+should_delete_user_db_with_custom_special_prefix(TestAuthDb) ->
+ User = "bar",
+ UserDbName = <<"userdb_$()+--/626172">>,
+ set_config("couch_peruser", "delete_dbs", "true"),
+ set_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+ create_user(TestAuthDb, User),
+ wait_for_db_create(UserDbName),
+ AfterCreate = lists:member(UserDbName, all_dbs()),
+ delete_user(TestAuthDb, User),
+ wait_for_db_delete(UserDbName),
+ delete_config("couch_peruser", "database_prefix"),
+ AfterDelete = lists:member(UserDbName, all_dbs()),
+ [
+ ?_assert(AfterCreate),
+ ?_assertNot(AfterDelete)
+ ].
+
+should_reflect_config_changes(TestAuthDb) ->
+ User = "baz",
+ UserDbName = <<"userdb-62617a">>,
+ set_config("couch_peruser", "delete_dbs", "true"),
+ create_user(TestAuthDb, User),
+ wait_for_db_create(UserDbName),
+ AfterCreate1 = lists:member(UserDbName, all_dbs()),
+ delete_user(TestAuthDb, User),
+ timer:sleep(?WAIT_FOR_USER_DELETE_TIMEOUT),
+ wait_for_db_delete(UserDbName),
+ AfterDelete1 = lists:member(UserDbName, all_dbs()),
+ create_user(TestAuthDb, User),
+ wait_for_db_create(UserDbName),
+ AfterCreate2 = lists:member(UserDbName, all_dbs()),
+ set_config("couch_peruser", "delete_dbs", "false"),
+ delete_user(TestAuthDb, User),
+ timer:sleep(?WAIT_FOR_USER_DELETE_TIMEOUT),
+ AfterDelete2 = lists:member(UserDbName, all_dbs()),
+ create_user(TestAuthDb, User),
+ wait_for_db_create(UserDbName),
+ set_config("couch_peruser", "delete_dbs", "true"),
+ delete_user(TestAuthDb, User),
+ wait_for_db_delete(UserDbName),
+ AfterDelete3 = lists:member(UserDbName, all_dbs()),
+ set_config("couch_peruser", "enable", "false"),
+ create_user(TestAuthDb, User),
+ timer:sleep(?WAIT_FOR_USER_DELETE_TIMEOUT),
+ AfterCreate3 = lists:member(UserDbName, all_dbs()),
+ [
+ ?_assert(AfterCreate1),
+ ?_assertNot(AfterDelete1),
+ ?_assert(AfterCreate2),
+ ?_assert(AfterDelete2),
+ ?_assertNot(AfterDelete3),
+ ?_assertNot(AfterCreate3)
+ ].
+
+
+should_add_user_to_db_admins(TestAuthDb) ->
+ User = "qux",
+ UserDbName = <<"userdb-717578">>,
+ create_user(TestAuthDb, User),
+ wait_for_db_create(UserDbName),
+ ?_assertEqual(
+ {[{<<"names">>,[<<"qux">>]}]},
+ proplists:get_value(<<"admins">>, get_security(UserDbName))).
+
+should_add_user_to_db_members(TestAuthDb) ->
+ User = "qux",
+ UserDbName = <<"userdb-717578">>,
+ create_user(TestAuthDb, User),
+ wait_for_db_create(UserDbName),
+ ?_assertEqual(
+ {[{<<"names">>,[<<"qux">>]}]},
+ proplists:get_value(<<"members">>, get_security(UserDbName))).
+
+should_not_remove_existing_db_admins(TestAuthDb) ->
+ User = "qux",
+ UserDbName = <<"userdb-717578">>,
+ SecurityProperties = [
+ {<<"admins">>,{[{<<"names">>,[<<"foo">>,<<"bar">>]}]}},
+ {<<"members">>,{[{<<"names">>,[<<"baz">>,<<"pow">>]}]}}
+ ],
+ create_db(UserDbName),
+ set_security(UserDbName, SecurityProperties),
+ create_user(TestAuthDb, User),
+ wait_for_security_create(<<"admins">>, User, UserDbName),
+ {AdminProperties} = proplists:get_value(<<"admins">>,
+ get_security(UserDbName)),
+ AdminNames = proplists:get_value(<<"names">>, AdminProperties),
+ [
+ ?_assert(lists:member(<<"foo">>, AdminNames)),
+ ?_assert(lists:member(<<"bar">>, AdminNames)),
+ ?_assert(lists:member(<<"qux">>, AdminNames))
+ ].
+
+should_not_remove_existing_db_members(TestAuthDb) ->
+ User = "qux",
+ UserDbName = <<"userdb-717578">>,
+ SecurityProperties = [
+ {<<"admins">>,{[{<<"names">>,[<<"pow">>,<<"wow">>]}]}},
+ {<<"members">>,{[{<<"names">>,[<<"pow">>,<<"wow">>]}]}}
+ ],
+ create_db(UserDbName),
+ set_security(UserDbName, SecurityProperties),
+ create_user(TestAuthDb, User),
+ wait_for_security_create(<<"members">>, User, UserDbName),
+ {MemberProperties} = proplists:get_value(<<"members">>,
+ get_security(UserDbName)),
+ MemberNames = proplists:get_value(<<"names">>, MemberProperties),
+ [
+ ?_assert(lists:member(<<"pow">>, MemberNames)),
+ ?_assert(lists:member(<<"wow">>, MemberNames)),
+ ?_assert(lists:member(<<"qux">>, MemberNames))
+ ].
+
+should_remove_user_from_db_admins(TestAuthDb) ->
+ User = "qux",
+ UserDbName = <<"userdb-717578">>,
+ SecurityProperties = [
+ {<<"admins">>,{[{<<"names">>,[<<"foo">>,<<"bar">>]}]}},
+ {<<"members">>,{[{<<"names">>,[<<"baz">>,<<"pow">>]}]}}
+ ],
+ create_db(UserDbName),
+ set_security(UserDbName, SecurityProperties),
+ create_user(TestAuthDb, User),
+ wait_for_security_create(<<"admins">>, User, UserDbName),
+ {AdminProperties} = proplists:get_value(<<"admins">>,
+ get_security(UserDbName)),
+ AdminNames = proplists:get_value(<<"names">>, AdminProperties),
+ FooBefore = lists:member(<<"foo">>, AdminNames),
+ BarBefore = lists:member(<<"bar">>, AdminNames),
+ QuxBefore = lists:member(<<"qux">>, AdminNames),
+ delete_user(TestAuthDb, User),
+ wait_for_security_delete(<<"admins">>, User, UserDbName),
+ {NewAdminProperties} = proplists:get_value(<<"admins">>,
+ get_security(UserDbName)),
+ NewAdminNames = proplists:get_value(<<"names">>, NewAdminProperties),
+ FooAfter = lists:member(<<"foo">>, NewAdminNames),
+ BarAfter = lists:member(<<"bar">>, NewAdminNames),
+ QuxAfter = lists:member(<<"qux">>, NewAdminNames),
+ [
+ ?_assert(FooBefore),
+ ?_assert(BarBefore),
+ ?_assert(QuxBefore),
+ ?_assert(FooAfter),
+ ?_assert(BarAfter),
+ ?_assertNot(QuxAfter)
+ ].
+
+should_remove_user_from_db_members(TestAuthDb) ->
+ User = "qux",
+ UserDbName = <<"userdb-717578">>,
+ SecurityProperties = [
+ {<<"admins">>,{[{<<"names">>,[<<"pow">>,<<"wow">>]}]}},
+ {<<"members">>,{[{<<"names">>,[<<"pow">>,<<"wow">>]}]}}
+ ],
+ create_db(UserDbName),
+ set_security(UserDbName, SecurityProperties),
+ create_user(TestAuthDb, User),
+ wait_for_security_create(<<"members">>, User, UserDbName),
+ {MemberProperties} = proplists:get_value(<<"members">>,
+ get_security(UserDbName)),
+ MemberNames = proplists:get_value(<<"names">>, MemberProperties),
+ PowBefore = lists:member(<<"pow">>, MemberNames),
+ WowBefore = lists:member(<<"wow">>, MemberNames),
+ QuxBefore = lists:member(<<"qux">>, MemberNames),
+ delete_user(TestAuthDb, User),
+ wait_for_security_delete(<<"members">>, User, UserDbName),
+ {NewMemberProperties} = proplists:get_value(<<"members">>,
+ get_security(UserDbName)),
+ NewMemberNames = proplists:get_value(<<"names">>, NewMemberProperties),
+ PowAfter = lists:member(<<"pow">>, NewMemberNames),
+ WowAfter = lists:member(<<"wow">>, NewMemberNames),
+ QuxAfter = lists:member(<<"qux">>, NewMemberNames),
+ [
+ ?_assert(PowBefore),
+ ?_assert(WowBefore),
+ ?_assert(QuxBefore),
+ ?_assert(PowAfter),
+ ?_assert(WowAfter),
+ ?_assertNot(QuxAfter)
+ ].
+
+
+wait_for_db_create(UserDbName) ->
+ test_util:wait(fun() ->
+ case all_dbs_with_errors() of
+ {error, _, _ , _} -> wait;
+ {ok, _, _, AllDbs} ->
+ case lists:member(UserDbName, AllDbs) of
+ true -> true;
+ false -> wait
+ end
+ end
+ end).
+
+wait_for_db_delete(UserDbName) ->
+ test_util:wait(fun() ->
+ case all_dbs_with_errors() of
+ {ok, 500, _ , _} -> wait;
+ {ok, _, _, AllDbs} ->
+ case not lists:member(UserDbName, AllDbs) of
+ true -> true;
+ false -> wait
+ end
+ end
+ end).
+
+wait_for_security_create(Type, User0, UserDbName) ->
+ User = ?l2b(User0),
+ test_util:wait(fun() ->
+ {Props} = proplists:get_value(Type, get_security(UserDbName)),
+ Names = proplists:get_value(<<"names">>, Props),
+ case lists:member(User, Names) of
+ true -> true;
+ false -> wait
+ end
+ end).
+
+wait_for_security_delete(Type, User0, UserDbName) ->
+ User = ?l2b(User0),
+ test_util:wait(fun() ->
+ {Props} = proplists:get_value(Type, get_security(UserDbName)),
+ Names = proplists:get_value(<<"names">>, Props),
+ case not lists:member(User, Names) of
+ true -> true;
+ false -> wait
+ end
+ end).
+
+couch_peruser_test_() ->
+ {
+ "couch_peruser test",
+ {
+ setup,
+ fun setup_all/0, fun teardown_all/1,
+ {
+ foreach,
+ fun setup/0, fun teardown/1,
+ [
+ fun should_create_anon_user_db_with_default/1,
+ fun should_create_anon_user_db_with_custom_prefix/1,
+ fun should_create_anon_user_db_with_custom_special_prefix/1,
+ fun should_create_user_db_with_default/1,
+ fun should_create_user_db_with_custom_prefix/1,
+ fun should_create_user_db_with_custom_special_prefix/1,
+ fun should_create_user_db_with_q4/1,
+ fun should_create_anon_user_db_with_q4/1,
+ fun should_not_delete_user_db/1,
+ fun should_delete_user_db/1,
+ fun should_delete_user_db_with_custom_prefix/1,
+ fun should_delete_user_db_with_custom_special_prefix/1,
+ fun should_reflect_config_changes/1,
+ fun should_add_user_to_db_admins/1,
+ fun should_add_user_to_db_members/1,
+ fun should_not_remove_existing_db_admins/1,
+ fun should_not_remove_existing_db_members/1,
+ fun should_remove_user_from_db_admins/1,
+ fun should_remove_user_from_db_members/1
+ ]
+ }
+ }
+ }.