summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Lehnardt <jan@apache.org>2022-08-06 17:53:28 +0200
committerJan Lehnardt <jan@apache.org>2022-12-16 16:56:18 +0100
commitd6863a73f9be7e01a28939f983e2fe072ffe2f7f (patch)
tree3bd6f5cf1f8e736010695346d78c9b8c5047f8b9
parent3776dca5bde1bc7549e81d862c95deee32b91213 (diff)
downloadcouchdb-d6863a73f9be7e01a28939f983e2fe072ffe2f7f.tar.gz
chore(access): erlfmt
-rw-r--r--src/chttpd/src/chttpd_db.erl11
-rw-r--r--src/chttpd/src/chttpd_view.erl28
-rw-r--r--src/couch/src/couch_access_native_proc.erl64
-rw-r--r--src/couch/src/couch_bt_engine.erl1
-rw-r--r--src/couch/src/couch_btree.erl8
-rw-r--r--src/couch/src/couch_db.erl199
-rw-r--r--src/couch/src/couch_db_updater.erl116
-rw-r--r--src/couch/src/couch_doc.erl7
-rw-r--r--src/couch/src/couch_util.erl5
-rw-r--r--src/couch/test/eunit/couchdb_access_tests.erl1293
-rw-r--r--src/couch/test/eunit/couchdb_update_conflicts_tests.erl3
-rw-r--r--src/couch_index/src/couch_index_updater.erl13
-rw-r--r--src/couch_index/src/couch_index_util.erl2
-rw-r--r--src/couch_mrview/src/couch_mrview.erl113
-rw-r--r--src/couch_mrview/src/couch_mrview_updater.erl56
-rw-r--r--src/couch_mrview/src/couch_mrview_util.erl2
-rw-r--r--src/couch_replicator/src/couch_replicator.erl17
-rw-r--r--src/couch_replicator/src/couch_replicator_scheduler_job.erl15
-rw-r--r--src/fabric/src/fabric_doc_update.erl6
19 files changed, 1224 insertions, 735 deletions
diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index 24ef1d0b9..50069a867 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -965,7 +965,7 @@ db_doc_req(#httpd{method = 'DELETE'} = Req, Db, DocId) ->
Rev ->
Body = {[{<<"_rev">>, ?l2b(Rev)}, {<<"_deleted">>, true}]}
end,
- Doc = #doc{revs=Revs,body=Body,deleted=true,access=Doc0#doc.access},
+ Doc = #doc{revs = Revs, body = Body, deleted = true, access = Doc0#doc.access},
send_updated_doc(Req, Db, DocId, couch_doc_from_req(Req, Db, DocId, Doc));
db_doc_req(#httpd{method = 'GET', mochi_req = MochiReq} = Req, Db, DocId) ->
#doc_query_args{
@@ -1416,7 +1416,7 @@ receive_request_data(Req, LenLeft) when LenLeft > 0 ->
receive_request_data(_Req, _) ->
throw(<<"expected more data">>).
-update_doc_result_to_json({#doc{id=Id,revs=Rev}, access}) ->
+update_doc_result_to_json({#doc{id = Id, revs = Rev}, access}) ->
update_doc_result_to_json({{Id, Rev}, access});
update_doc_result_to_json({error, _} = Error) ->
{_Code, Err, Msg} = chttpd:error_info(Error),
@@ -2001,13 +2001,12 @@ parse_shards_opt("placement", Req, Default) ->
throw({bad_request, Err})
end
end;
-
-
parse_shards_opt("access", Req, Value) when is_list(Value) ->
parse_shards_opt("access", Req, list_to_existing_atom(Value));
parse_shards_opt("access", _Req, Value) when Value =:= true ->
case config:get_boolean("per_doc_access", "enabled", false) of
- true -> true;
+ true ->
+ true;
false ->
Err = ?l2b(["The `access` option is not available on this CouchDB installation."]),
throw({bad_request, Err})
@@ -2017,7 +2016,6 @@ parse_shards_opt("access", _Req, Value) when Value =:= false ->
parse_shards_opt("access", _Req, _Value) ->
Err = ?l2b(["The `access` value should be a boolean."]),
throw({bad_request, Err});
-
parse_shards_opt(Param, Req, Default) ->
couch_log:error("~n parse_shards_opt Param: ~p, Default: ~p~n", [Param, Default]),
Val = chttpd:qs_value(Req, Param, Default),
@@ -2027,7 +2025,6 @@ parse_shards_opt(Param, Req, Default) ->
false -> throw({bad_request, Err})
end.
-
parse_engine_opt(Req) ->
case chttpd:qs_value(Req, "engine") of
undefined ->
diff --git a/src/chttpd/src/chttpd_view.erl b/src/chttpd/src/chttpd_view.erl
index f74088dbc..44459b3cf 100644
--- a/src/chttpd/src/chttpd_view.erl
+++ b/src/chttpd/src/chttpd_view.erl
@@ -69,20 +69,20 @@ fabric_query_view(Db, Req, DDoc, ViewName, Args) ->
Max = chttpd:chunked_response_buffer_size(),
VAcc = #vacc{db = Db, req = Req, threshold = Max},
Options = [{user_ctx, Req#httpd.user_ctx}],
-% {ok, Resp} = fabric:query_view(Db, Options, DDoc, ViewName,
-% fun view_cb/2, VAcc, Args),
-% {ok, Resp#vacc.resp}.
-% % TODO: This might just be a debugging leftover, we might be able
-% % to undo this by just returning {ok, Resp#vacc.resp}
-% % However, this *might* be here because we need to handle
-% % errors here now, because access might tell us to.
-% case fabric:query_view(Db, Options, DDoc, ViewName,
-% fun view_cb/2, VAcc, Args) of
-% {ok, Resp} ->
-% {ok, Resp#vacc.resp};
-% {error, Error} ->
-% throw(Error)
-% end.
+ % {ok, Resp} = fabric:query_view(Db, Options, DDoc, ViewName,
+ % fun view_cb/2, VAcc, Args),
+ % {ok, Resp#vacc.resp}.
+ % % TODO: This might just be a debugging leftover, we might be able
+ % % to undo this by just returning {ok, Resp#vacc.resp}
+ % % However, this *might* be here because we need to handle
+ % % errors here now, because access might tell us to.
+ % case fabric:query_view(Db, Options, DDoc, ViewName,
+ % fun view_cb/2, VAcc, Args) of
+ % {ok, Resp} ->
+ % {ok, Resp#vacc.resp};
+ % {error, Error} ->
+ % throw(Error)
+ % end.
{ok, Resp} = fabric:query_view(
Db,
diff --git a/src/couch/src/couch_access_native_proc.erl b/src/couch/src/couch_access_native_proc.erl
index 965b124de..38c8e5738 100644
--- a/src/couch/src/couch_access_native_proc.erl
+++ b/src/couch/src/couch_access_native_proc.erl
@@ -13,7 +13,6 @@
-module(couch_access_native_proc).
-behavior(gen_server).
-
-export([
start_link/0,
set_timeout/2,
@@ -29,71 +28,55 @@
code_change/3
]).
-
-record(st, {
indexes = [],
- timeout = 5000 % TODO: make configurable
+ % TODO: make configurable
+ timeout = 5000
}).
start_link() ->
gen_server:start_link(?MODULE, [], []).
-
set_timeout(Pid, TimeOut) when is_integer(TimeOut), TimeOut > 0 ->
gen_server:call(Pid, {set_timeout, TimeOut}).
-
prompt(Pid, Data) ->
gen_server:call(Pid, {prompt, Data}).
-
init(_) ->
{ok, #st{}}.
-
terminate(_Reason, _St) ->
ok.
-
handle_call({set_timeout, TimeOut}, _From, St) ->
- {reply, ok, St#st{timeout=TimeOut}};
-
+ {reply, ok, St#st{timeout = TimeOut}};
handle_call({prompt, [<<"reset">>]}, _From, St) ->
- {reply, true, St#st{indexes=[]}};
-
+ {reply, true, St#st{indexes = []}};
handle_call({prompt, [<<"reset">>, _QueryConfig]}, _From, St) ->
- {reply, true, St#st{indexes=[]}};
-
+ {reply, true, St#st{indexes = []}};
handle_call({prompt, [<<"add_fun">>, IndexInfo]}, _From, St) ->
{reply, true, St};
-
handle_call({prompt, [<<"map_doc">>, Doc]}, _From, St) ->
{reply, map_doc(St, mango_json:to_binary(Doc)), St};
-
handle_call({prompt, [<<"reduce">>, _, _]}, _From, St) ->
{reply, null, St};
-
handle_call({prompt, [<<"rereduce">>, _, _]}, _From, St) ->
{reply, null, St};
-
handle_call({prompt, [<<"index_doc">>, Doc]}, _From, St) ->
{reply, [[]], St};
-
handle_call(Msg, _From, St) ->
{stop, {invalid_call, Msg}, {invalid_call, Msg}, St}.
handle_cast(garbage_collect, St) ->
erlang:garbage_collect(),
{noreply, St};
-
handle_cast(Msg, St) ->
{stop, {invalid_cast, Msg}, St}.
-
handle_info(Msg, St) ->
{stop, {invalid_info, Msg}, St}.
-
code_change(_OldVsn, St, _Extra) ->
{ok, St}.
@@ -115,7 +98,8 @@ code_change(_OldVsn, St, _Extra) ->
map_doc(_St, {Doc}) ->
case couch_util:get_value(<<"_access">>, Doc) of
undefined ->
- [[],[]]; % do not index this doc
+ % do not index this doc
+ [[], []];
Access when is_list(Access) ->
Id = couch_util:get_value(<<"_id">>, Doc),
Rev = couch_util:get_value(<<"_rev">>, Doc),
@@ -123,21 +107,33 @@ map_doc(_St, {Doc}) ->
Deleted = couch_util:get_value(<<"_deleted">>, Doc, false),
BodySp = couch_util:get_value(<<"_body_sp">>, Doc),
% by-access-id
- ById = case Deleted of
- false ->
- lists:map(fun(UserOrRole) -> [
- [[UserOrRole, Id], Rev]
- ] end, Access);
- _True -> [[]]
- end,
+ ById =
+ case Deleted of
+ false ->
+ lists:map(
+ fun(UserOrRole) ->
+ [
+ [[UserOrRole, Id], Rev]
+ ]
+ end,
+ Access
+ );
+ _True ->
+ [[]]
+ end,
% by-access-seq
- BySeq = lists:map(fun(UserOrRole) -> [
- [[UserOrRole, Seq], [{rev, Rev}, {deleted, Deleted}, {body_sp, BodySp}]]
- ] end, Access),
+ BySeq = lists:map(
+ fun(UserOrRole) ->
+ [
+ [[UserOrRole, Seq], [{rev, Rev}, {deleted, Deleted}, {body_sp, BodySp}]]
+ ]
+ end,
+ Access
+ ),
ById ++ BySeq;
Else ->
% TODO: no comprende: should not be needed once we implement
% _access field validation
- [[],[]]
+ [[], []]
end.
diff --git a/src/couch/src/couch_bt_engine.erl b/src/couch/src/couch_bt_engine.erl
index bd778f33b..d653a8eea 100644
--- a/src/couch/src/couch_bt_engine.erl
+++ b/src/couch/src/couch_bt_engine.erl
@@ -672,7 +672,6 @@ id_tree_split(#full_doc_info{} = Info) ->
id_tree_join(Id, {HighSeq, Deleted, DiskTree}) ->
% Handle old formats before data_size was added
id_tree_join(Id, {HighSeq, Deleted, #size_info{}, DiskTree});
-
id_tree_join(Id, {HighSeq, Deleted, Sizes, DiskTree}) ->
id_tree_join(Id, {HighSeq, Deleted, Sizes, DiskTree, []});
id_tree_join(Id, {HighSeq, Deleted, Sizes, DiskTree, Access}) ->
diff --git a/src/couch/src/couch_btree.erl b/src/couch/src/couch_btree.erl
index d7ca7bab4..b908421f2 100644
--- a/src/couch/src/couch_btree.erl
+++ b/src/couch/src/couch_btree.erl
@@ -116,9 +116,11 @@ full_reduce_with_options(Bt, Options0) ->
end,
[UserName] = proplists:get_value(start_key, Options0, <<"">>),
EndKey = {[UserName, {[]}]},
- Options = Options0 ++ [
- {end_key, EndKey}
- ],
+ Options =
+ Options0 ++
+ [
+ {end_key, EndKey}
+ ],
fold_reduce(Bt, CountFun, 0, Options).
size(#btree{root = nil}) ->
diff --git a/src/couch/src/couch_db.erl b/src/couch/src/couch_db.erl
index 7c7a67500..cc2810ae5 100644
--- a/src/couch/src/couch_db.erl
+++ b/src/couch/src/couch_db.erl
@@ -140,7 +140,8 @@
]).
-include_lib("couch/include/couch_db.hrl").
--include_lib("couch_mrview/include/couch_mrview.hrl"). % TODO: can we do without this?
+% TODO: can we do without this?
+-include_lib("couch_mrview/include/couch_mrview.hrl").
-include("couch_db_int.hrl").
-define(DBNAME_REGEX,
@@ -292,7 +293,7 @@ wait_for_compaction(#db{main_pid = Pid} = Db, Timeout) ->
is_compacting(DbName) ->
couch_server:is_compacting(DbName).
-has_access_enabled(#db{access=true}) -> true;
+has_access_enabled(#db{access = true}) -> true;
has_access_enabled(_) -> false.
is_read_from_ddoc_cache(Options) ->
@@ -308,10 +309,11 @@ open_doc(Db, IdOrDocInfo) ->
open_doc(Db, Id, Options0) ->
increment_stat(Db, [couchdb, database_reads]),
- Options = case has_access_enabled(Db) of
- true -> Options0 ++ [conflicts];
- _Else -> Options0
- end,
+ Options =
+ case has_access_enabled(Db) of
+ true -> Options0 ++ [conflicts];
+ _Else -> Options0
+ end,
case open_doc_int(Db, Id, Options) of
{ok, #doc{deleted = true} = Doc} ->
case lists:member(deleted, Options) of
@@ -791,8 +793,8 @@ security_error_type(#user_ctx{name = null}) ->
security_error_type(#user_ctx{name = _}) ->
forbidden.
-is_per_user_ddoc(#doc{access=[]}) -> false;
-is_per_user_ddoc(#doc{access=[<<"_users">>]}) -> false;
+is_per_user_ddoc(#doc{access = []}) -> false;
+is_per_user_ddoc(#doc{access = [<<"_users">>]}) -> false;
is_per_user_ddoc(_) -> true.
validate_access(Db, Doc) ->
@@ -801,17 +803,20 @@ validate_access(Db, Doc) ->
validate_access(Db, Doc, Options) ->
validate_access1(has_access_enabled(Db), Db, Doc, Options).
-validate_access1(false, _Db, _Doc, _Options) -> ok;
-validate_access1(true, Db, #doc{meta=Meta}=Doc, Options) ->
+validate_access1(false, _Db, _Doc, _Options) ->
+ ok;
+validate_access1(true, Db, #doc{meta = Meta} = Doc, Options) ->
case proplists:get_value(conflicts, Meta) of
- undefined -> % no conflicts
+ % no conflicts
+ undefined ->
case is_read_from_ddoc_cache(Options) andalso is_per_user_ddoc(Doc) of
true -> throw({not_found, missing});
_False -> validate_access2(Db, Doc)
end;
- _Else -> % only admins can read conflicted docs in _access dbs
- % TODO: expand: if leaves agree on _access, then a user should be able
- % to proceed normally, only if they disagree should this become admin-only
+ % only admins can read conflicted docs in _access dbs
+ _Else ->
+ % TODO: expand: if leaves agree on _access, then a user should be able
+ % to proceed normally, only if they disagree should this become admin-only
case is_admin(Db) of
true -> ok;
_Else2 -> throw({forbidden, <<"document is in conflict">>})
@@ -824,36 +829,35 @@ validate_access3(true) -> ok;
% TODO: fix language
validate_access3(_) -> throw({forbidden, <<"can't touch this">>}).
-check_access(Db, #doc{access=Access}) ->
+check_access(Db, #doc{access = Access}) ->
check_access(Db, Access);
check_access(Db, Access) ->
%couch_log:notice("~n Db.user_ctx: ~p, Access: ~p ~n", [Db#db.user_ctx, Access]),
#user_ctx{
- name=UserName,
- roles=UserRoles
+ name = UserName,
+ roles = UserRoles
} = Db#db.user_ctx,
case Access of
- [] ->
- % if doc has no _access, userCtX must be admin
- is_admin(Db);
- Access ->
- % if doc has _access, userCtx must be admin OR matching user or role
- % _access = ["a", "b", ]
- case is_admin(Db) of
- true ->
- true;
- _ ->
- case {check_name(UserName, Access), check_roles(UserRoles, Access)} of
- {true, _} -> true;
- {_, true} -> true;
- _ -> false
+ [] ->
+ % if doc has no _access, userCtX must be admin
+ is_admin(Db);
+ Access ->
+ % if doc has _access, userCtx must be admin OR matching user or role
+ % _access = ["a", "b", ]
+ case is_admin(Db) of
+ true ->
+ true;
+ _ ->
+ case {check_name(UserName, Access), check_roles(UserRoles, Access)} of
+ {true, _} -> true;
+ {_, true} -> true;
+ _ -> false
+ end
end
- end
end.
check_name(null, _Access) -> true;
-check_name(UserName, Access) ->
- lists:member(UserName, Access).
+check_name(UserName, Access) -> lists:member(UserName, Access).
% nicked from couch_db:check_security
% TODO: might need DRY
@@ -1003,14 +1007,14 @@ group_alike_docs([Doc | Rest], [Bucket | RestBuckets]) ->
end.
validate_doc_update(#db{} = Db, #doc{id = <<"_design/", _/binary>>} = Doc, _GetDiskDocFun) ->
- case couch_doc:has_access(Doc) of
- true ->
- validate_ddoc(Db, Doc);
- _Else ->
- case catch check_is_admin(Db) of
- ok -> validate_ddoc(Db, Doc);
- Error -> Error
- end
+ case couch_doc:has_access(Doc) of
+ true ->
+ validate_ddoc(Db, Doc);
+ _Else ->
+ case catch check_is_admin(Db) of
+ ok -> validate_ddoc(Db, Doc);
+ Error -> Error
+ end
end;
validate_doc_update(#db{validate_doc_funs = undefined} = Db, Doc, Fun) ->
ValidationFuns = load_validation_funs(Db),
@@ -1411,24 +1415,28 @@ validate_update(Db, Doc) ->
Error -> Error
end.
-
validate_docs_access(Db, DocBuckets, DocErrors) ->
- validate_docs_access1(Db, DocBuckets, {[], DocErrors}).
+ validate_docs_access1(Db, DocBuckets, {[], DocErrors}).
validate_docs_access1(_Db, [], {DocBuckets0, DocErrors}) ->
- DocBuckets1 = lists:reverse(lists:map(fun lists:reverse/1, DocBuckets0)),
- DocBuckets = case DocBuckets1 of
- [[]] -> [];
- Else -> Else
- end,
+ DocBuckets1 = lists:reverse(lists:map(fun lists:reverse/1, DocBuckets0)),
+ DocBuckets =
+ case DocBuckets1 of
+ [[]] -> [];
+ Else -> Else
+ end,
{ok, DocBuckets, lists:reverse(DocErrors)};
-validate_docs_access1(Db, [DocBucket|RestBuckets], {DocAcc, ErrorAcc}) ->
- {NewBuckets, NewErrors} = lists:foldl(fun(Doc, {Acc, ErrAcc}) ->
- case catch validate_access(Db, Doc) of
- ok -> {[Doc|Acc], ErrAcc};
- Error -> {Acc, [{doc_tag(Doc), Error}|ErrAcc]}
- end
- end, {[], ErrorAcc}, DocBucket),
+validate_docs_access1(Db, [DocBucket | RestBuckets], {DocAcc, ErrorAcc}) ->
+ {NewBuckets, NewErrors} = lists:foldl(
+ fun(Doc, {Acc, ErrAcc}) ->
+ case catch validate_access(Db, Doc) of
+ ok -> {[Doc | Acc], ErrAcc};
+ Error -> {Acc, [{doc_tag(Doc), Error} | ErrAcc]}
+ end
+ end,
+ {[], ErrorAcc},
+ DocBucket
+ ),
validate_docs_access1(Db, RestBuckets, {[NewBuckets | DocAcc], NewErrors}).
update_docs(Db, Docs0, Options, ?REPLICATED_CHANGES) ->
@@ -1461,28 +1469,34 @@ update_docs(Db, Docs0, Options, ?REPLICATED_CHANGES) ->
[merge_conflicts | Options]
),
case couch_db:has_access_enabled(Db) of
- false ->
- % we’re done here
- {ok, DocErrors};
- _ ->
- AccessViolations = lists:filter(fun({_Ref, Tag}) -> Tag =:= access end, Results),
- case length(AccessViolations) of
- 0 ->
- % we’re done here
- {ok, DocErrors};
- _ ->
- % dig out FDIs from Docs matching our tags/refs
- DocsDict = lists:foldl(fun(Doc, Dict) ->
- Tag = doc_tag(Doc),
- dict:store(Tag, Doc, Dict)
- end, dict:new(), Docs),
- AccessResults = lists:map(fun({Ref, Access}) ->
- { dict:fetch(Ref, DocsDict), Access }
- end, AccessViolations),
- {ok, AccessResults}
- end
- end;
-
+ false ->
+ % we’re done here
+ {ok, DocErrors};
+ _ ->
+ AccessViolations = lists:filter(fun({_Ref, Tag}) -> Tag =:= access end, Results),
+ case length(AccessViolations) of
+ 0 ->
+ % we’re done here
+ {ok, DocErrors};
+ _ ->
+ % dig out FDIs from Docs matching our tags/refs
+ DocsDict = lists:foldl(
+ fun(Doc, Dict) ->
+ Tag = doc_tag(Doc),
+ dict:store(Tag, Doc, Dict)
+ end,
+ dict:new(),
+ Docs
+ ),
+ AccessResults = lists:map(
+ fun({Ref, Access}) ->
+ {dict:fetch(Ref, DocsDict), Access}
+ end,
+ AccessViolations
+ ),
+ {ok, AccessResults}
+ end
+ end;
update_docs(Db, Docs0, Options, ?INTERACTIVE_EDIT) ->
Docs = tag_docs(Docs0),
@@ -2007,7 +2021,10 @@ open_doc_revs_int(Db, IdRevs, Options) ->
% we have the rev in our list but know nothing about it
{{not_found, missing}, {Pos, Rev}};
#leaf{deleted = IsDeleted, ptr = SummaryPtr} ->
- {ok, make_doc(Db, Id, IsDeleted, SummaryPtr, FoundRevPath, Access)}
+ {ok,
+ make_doc(
+ Db, Id, IsDeleted, SummaryPtr, FoundRevPath, Access
+ )}
end
end,
FoundRevs
@@ -2029,29 +2046,33 @@ open_doc_revs_int(Db, IdRevs, Options) ->
open_doc_int(Db, <<?LOCAL_DOC_PREFIX, _/binary>> = Id, Options) ->
case couch_db_engine:open_local_docs(Db, [Id]) of
[#doc{} = Doc] ->
- case Doc#doc.body of
- { Body } ->
- Access = couch_util:get_value(<<"_access">>, Body),
- apply_open_options(Db, {ok, Doc#doc{access = Access}}, Options);
- _Else ->
- apply_open_options(Db, {ok, Doc}, Options)
- end;
+ case Doc#doc.body of
+ {Body} ->
+ Access = couch_util:get_value(<<"_access">>, Body),
+ apply_open_options(Db, {ok, Doc#doc{access = Access}}, Options);
+ _Else ->
+ apply_open_options(Db, {ok, Doc}, Options)
+ end;
[not_found] ->
{not_found, missing}
end;
open_doc_int(Db, #doc_info{id = Id, revs = [RevInfo | _], access = Access} = DocInfo, Options) ->
#rev_info{deleted = IsDeleted, rev = {Pos, RevId}, body_sp = Bp} = RevInfo,
Doc = make_doc(Db, Id, IsDeleted, Bp, {Pos, [RevId]}, Access),
- apply_open_options(Db,
+ apply_open_options(
+ Db,
{ok, Doc#doc{meta = doc_meta_info(DocInfo, [], Options)}},
Options
);
-open_doc_int(Db, #full_doc_info{id = Id, rev_tree = RevTree, access = Access} = FullDocInfo, Options) ->
+open_doc_int(
+ Db, #full_doc_info{id = Id, rev_tree = RevTree, access = Access} = FullDocInfo, Options
+) ->
#doc_info{revs = [#rev_info{deleted = IsDeleted, rev = Rev, body_sp = Bp} | _]} =
DocInfo = couch_doc:to_doc_info(FullDocInfo),
{[{_, RevPath}], []} = couch_key_tree:get(RevTree, [Rev]),
Doc = make_doc(Db, Id, IsDeleted, Bp, RevPath, Access),
- apply_open_options(Db,
+ apply_open_options(
+ Db,
{ok, Doc#doc{meta = doc_meta_info(DocInfo, RevTree, Options)}},
Options
);
diff --git a/src/couch/src/couch_db_updater.erl b/src/couch/src/couch_db_updater.erl
index 75b1afc92..02136d83b 100644
--- a/src/couch/src/couch_db_updater.erl
+++ b/src/couch/src/couch_db_updater.erl
@@ -25,8 +25,8 @@
-define(DEFAULT_MAX_PARTITION_SIZE, 16#280000000).
-define(DEFAULT_SECURITY_OBJECT, [
- {<<"members">>,{[{<<"roles">>,[<<"_admin">>]}]}},
- {<<"admins">>, {[{<<"roles">>,[<<"_admin">>]}]}}
+ {<<"members">>, {[{<<"roles">>, [<<"_admin">>]}]}},
+ {<<"admins">>, {[{<<"roles">>, [<<"_admin">>]}]}}
]).
-record(merge_acc, {
@@ -266,10 +266,11 @@ sort_and_tag_grouped_docs(Client, GroupedDocs) ->
% duplicate documents if the incoming groups are not sorted, so as a sanity
% check we sort them again here. See COUCHDB-2735.
Cmp = fun
- ([], []) -> false; % TODO: re-evaluate this addition, might be
- % superflous now
- ([#doc{id=A}|_], [#doc{id=B}|_]) -> A < B
- end,
+ % TODO: re-evaluate this addition, might be
+ ([], []) -> false;
+ % superflous now
+ ([#doc{id = A} | _], [#doc{id = B} | _]) -> A < B
+ end,
lists:map(
fun(DocGroup) ->
[{Client, maybe_tag_doc(D)} || D <- DocGroup]
@@ -674,12 +675,12 @@ update_docs_int(Db, DocsList, LocalDocs, MergeConflicts, UserCtx) ->
UpdateSeq = couch_db_engine:get_update_seq(Db),
RevsLimit = couch_db_engine:get_revs_limit(Db),
- Ids = [Id || [{_Client, #doc{id=Id}}|_] <- DocsList],
+ Ids = [Id || [{_Client, #doc{id = Id}} | _] <- DocsList],
% TODO: maybe a perf hit, instead of zip3-ing existing Accesses into
% our doc lists, maybe find 404 docs differently down in
% validate_docs_access (revs is [], which we can then use
% to skip validation as we know it is the first doc rev)
- Accesses = [Access || [{_Client, #doc{access=Access}}|_] <- DocsList],
+ Accesses = [Access || [{_Client, #doc{access = Access}} | _] <- DocsList],
% lookup up the old documents, if they exist.
OldDocLookups = couch_db_engine:open_docs(Db, Ids),
@@ -688,7 +689,7 @@ update_docs_int(Db, DocsList, LocalDocs, MergeConflicts, UserCtx) ->
(_Id, #full_doc_info{} = FDI, _Access) ->
FDI;
(Id, not_found, Access) ->
- #full_doc_info{id=Id,access=Access}
+ #full_doc_info{id = Id, access = Access}
end,
Ids,
OldDocLookups,
@@ -737,12 +738,12 @@ update_docs_int(Db, DocsList, LocalDocs, MergeConflicts, UserCtx) ->
%couch_log:notice("~nDb: ~p, UserCtx: ~p~n", [Db, UserCtx]),
-
- { DocsListValidated, OldDocInfosValidated } = validate_docs_access(Db, UserCtx, DocsList, OldDocInfos),
+ {DocsListValidated, OldDocInfosValidated} = validate_docs_access(
+ Db, UserCtx, DocsList, OldDocInfos
+ ),
%couch_log:notice("~nDocsListValidated: ~p, OldDocInfosValidated: ~p~n", [DocsListValidated, OldDocInfosValidated]),
-
{ok, AccOut} = merge_rev_trees(DocsListValidated, OldDocInfosValidated, AccIn),
#merge_acc{
add_infos = NewFullDocInfos,
@@ -771,7 +772,7 @@ update_docs_int(Db, DocsList, LocalDocs, MergeConflicts, UserCtx) ->
% Check if we just updated any non-access design documents,
% and update the validation funs if we did.
- NonAccessIds = [Id || [{_Client, #doc{id=Id,access=[]}}|_] <- DocsList],
+ NonAccessIds = [Id || [{_Client, #doc{id = Id, access = []}} | _] <- DocsList],
UpdatedDDocIds = lists:flatmap(
fun
(<<"_design/", _/binary>> = Id) -> [Id];
@@ -789,55 +790,68 @@ update_docs_int(Db, DocsList, LocalDocs, MergeConflicts, UserCtx) ->
% true;
% at this point, we already validated this Db is access enabled, so do the checks right away.
-check_access(Db, UserCtx, Access) -> couch_db:check_access(Db#db{user_ctx=UserCtx}, Access).
+check_access(Db, UserCtx, Access) -> couch_db:check_access(Db#db{user_ctx = UserCtx}, Access).
validate_docs_access(Db, UserCtx, DocsList, OldDocInfos) ->
case couch_db:has_access_enabled(Db) of
true -> validate_docs_access_int(Db, UserCtx, DocsList, OldDocInfos);
- _Else -> { DocsList, OldDocInfos }
+ _Else -> {DocsList, OldDocInfos}
end.
validate_docs_access_int(Db, UserCtx, DocsList, OldDocInfos) ->
validate_docs_access(Db, UserCtx, DocsList, OldDocInfos, [], []).
validate_docs_access(_Db, _UserCtx, [], [], DocsListValidated, OldDocInfosValidated) ->
- { lists:reverse(DocsListValidated), lists:reverse(OldDocInfosValidated) };
-validate_docs_access(Db, UserCtx, [Docs | DocRest], [OldInfo | OldInfoRest], DocsListValidated, OldDocInfosValidated) ->
+ {lists:reverse(DocsListValidated), lists:reverse(OldDocInfosValidated)};
+validate_docs_access(
+ Db, UserCtx, [Docs | DocRest], [OldInfo | OldInfoRest], DocsListValidated, OldDocInfosValidated
+) ->
% loop over Docs as {Client, NewDoc}
% validate Doc
% if valid, then put back in Docs
% if not, then send_result and skip
%couch_log:notice("~nvalidate_docs_access() UserCtx: ~p, Docs: ~p, OldInfo: ~p~n", [UserCtx, Docs, OldInfo]),
- NewDocs = lists:foldl(fun({ Client, Doc }, Acc) ->
- %couch_log:notice("~nvalidate_docs_access lists:foldl() Doc: ~p Doc#doc.access: ~p~n", [Doc, Doc#doc.access]),
+ NewDocs = lists:foldl(
+ fun({Client, Doc}, Acc) ->
+ %couch_log:notice("~nvalidate_docs_access lists:foldl() Doc: ~p Doc#doc.access: ~p~n", [Doc, Doc#doc.access]),
- % check if we are allowed to update the doc, skip when new doc
- OldDocMatchesAccess = case OldInfo#full_doc_info.rev_tree of
- [] -> true;
- _ -> check_access(Db, UserCtx, OldInfo#full_doc_info.access)
- end,
+ % check if we are allowed to update the doc, skip when new doc
+ OldDocMatchesAccess =
+ case OldInfo#full_doc_info.rev_tree of
+ [] -> true;
+ _ -> check_access(Db, UserCtx, OldInfo#full_doc_info.access)
+ end,
- NewDocMatchesAccess = check_access(Db, UserCtx, Doc#doc.access),
- %couch_log:notice("~nvalidate_docs_access lists:foldl() OldDocMatchesAccess: ~p, NewDocMatchesAccess: ~p, andalso: ~p~n", [OldDocMatchesAccess, NewDocMatchesAccess, OldDocMatchesAccess andalso NewDocMatchesAccess]),
+ NewDocMatchesAccess = check_access(Db, UserCtx, Doc#doc.access),
+ %couch_log:notice("~nvalidate_docs_access lists:foldl() OldDocMatchesAccess: ~p, NewDocMatchesAccess: ~p, andalso: ~p~n", [OldDocMatchesAccess, NewDocMatchesAccess, OldDocMatchesAccess andalso NewDocMatchesAccess]),
- case OldDocMatchesAccess andalso NewDocMatchesAccess of
- true -> % if valid, then send to DocsListValidated, OldDocsInfo
+ case OldDocMatchesAccess andalso NewDocMatchesAccess of
+ % if valid, then send to DocsListValidated, OldDocsInfo
+ true ->
% and store the access context on the new doc
- [{Client, Doc} | Acc];
- false -> % if invalid, then send_result tagged `access`(c.f. `conflict)
- % and don’t add to DLV, nor ODI
- send_result(Client, Doc, access),
- Acc
- end
- end, [], Docs),
-
- { NewDocsListValidated, NewOldDocInfosValidated } = case length(NewDocs) of
- 0 -> % we sent out all docs as invalid access, drop the old doc info associated with it
- { [NewDocs | DocsListValidated], OldDocInfosValidated };
- _ ->
- { [NewDocs | DocsListValidated], [OldInfo | OldDocInfosValidated] }
- end,
- validate_docs_access(Db, UserCtx, DocRest, OldInfoRest, NewDocsListValidated, NewOldDocInfosValidated).
+ [{Client, Doc} | Acc];
+ % if invalid, then send_result tagged `access`(c.f. `conflict)
+ false ->
+ % and don’t add to DLV, nor ODI
+ send_result(Client, Doc, access),
+ Acc
+ end
+ end,
+ [],
+ Docs
+ ),
+
+ {NewDocsListValidated, NewOldDocInfosValidated} =
+ case length(NewDocs) of
+ % we sent out all docs as invalid access, drop the old doc info associated with it
+ 0 ->
+ {[NewDocs | DocsListValidated], OldDocInfosValidated};
+ _ ->
+ {[NewDocs | DocsListValidated], [OldInfo | OldDocInfosValidated]}
+ end,
+ validate_docs_access(
+ Db, UserCtx, DocRest, OldInfoRest, NewDocsListValidated, NewOldDocInfosValidated
+ ).
apply_local_docs_access(Db, Docs) ->
apply_local_docs_access1(couch_db:has_access_enabled(Db), Docs).
@@ -845,10 +859,13 @@ apply_local_docs_access(Db, Docs) ->
apply_local_docs_access1(false, Docs) ->
Docs;
apply_local_docs_access1(true, Docs) ->
- lists:map(fun({Client, #doc{access = Access, body = {Body}} = Doc}) ->
- Doc1 = Doc#doc{body = {[{<<"_access">>, Access} | Body]}},
- {Client, Doc1}
- end, Docs).
+ lists:map(
+ fun({Client, #doc{access = Access, body = {Body}} = Doc}) ->
+ Doc1 = Doc#doc{body = {[{<<"_access">>, Access} | Body]}},
+ {Client, Doc1}
+ end,
+ Docs
+ ).
update_local_doc_revs(Docs) ->
lists:foldl(
@@ -1038,14 +1055,15 @@ get_meta_body_size(Meta) ->
default_security_object(<<"shards/", _/binary>>) ->
case config:get("couchdb", "default_security", "admin_only") of
- "admin_only" -> ?DEFAULT_SECURITY_OBJECT;
+ "admin_only" ->
+ ?DEFAULT_SECURITY_OBJECT;
Everyone when Everyone == "everyone"; Everyone == "admin_local" ->
[]
end;
default_security_object(_DbName) ->
case config:get("couchdb", "default_security", "admin_only") of
Admin when Admin == "admin_only"; Admin == "admin_local" ->
- ?DEFAULT_SECURITY_OBJECT;
+ ?DEFAULT_SECURITY_OBJECT;
"everyone" ->
[]
end.
diff --git a/src/couch/src/couch_doc.erl b/src/couch/src/couch_doc.erl
index 70d593300..dec3301d4 100644
--- a/src/couch/src/couch_doc.erl
+++ b/src/couch/src/couch_doc.erl
@@ -430,7 +430,10 @@ to_doc_info_path(#full_doc_info{id = Id, rev_tree = Tree, update_seq = FDISeq, a
),
[{_RevInfo, WinPath} | _] = SortedRevInfosAndPath,
RevInfos = [RevInfo || {RevInfo, _Path} <- SortedRevInfosAndPath],
- {#doc_info{id = Id, high_seq = max_seq(Tree, FDISeq), revs = RevInfos, access = Access}, WinPath}.
+ {
+ #doc_info{id = Id, high_seq = max_seq(Tree, FDISeq), revs = RevInfos, access = Access},
+ WinPath
+ }.
rev_info({#leaf{} = Leaf, {Pos, [RevId | _]}}) ->
#rev_info{
@@ -472,7 +475,7 @@ is_deleted(Tree) ->
get_access({Props}) ->
get_access(couch_doc:from_json_obj({Props}));
-get_access(#doc{access=Access}) ->
+get_access(#doc{access = Access}) ->
Access.
has_access(Doc) ->
diff --git a/src/couch/src/couch_util.erl b/src/couch/src/couch_util.erl
index cb29ce8b3..4199ceb9c 100644
--- a/src/couch/src/couch_util.erl
+++ b/src/couch/src/couch_util.erl
@@ -876,8 +876,7 @@ validate_design_access(Db, DDoc) ->
validate_design_access1(DDoc, couch_db:has_access_enabled(Db)).
validate_design_access1(_DDoc, false) -> ok;
-validate_design_access1(DDoc, true) ->
- is_users_ddoc(DDoc).
+validate_design_access1(DDoc, true) -> is_users_ddoc(DDoc).
-is_users_ddoc(#doc{access=[<<"_users">>]}) -> ok;
+is_users_ddoc(#doc{access = [<<"_users">>]}) -> ok;
is_users_ddoc(_) -> throw({forbidden, <<"per-user ddoc access">>}).
diff --git a/src/couch/test/eunit/couchdb_access_tests.erl b/src/couch/test/eunit/couchdb_access_tests.erl
index 33fb576ff..126e43fb2 100644
--- a/src/couch/test/eunit/couchdb_access_tests.erl
+++ b/src/couch/test/eunit/couchdb_access_tests.erl
@@ -18,10 +18,12 @@
-define(ADMIN_REQ_HEADERS, [?CONTENT_JSON, {basic_auth, {"a", "a"}}]).
-define(USERX_REQ_HEADERS, [?CONTENT_JSON, {basic_auth, {"x", "x"}}]).
-define(USERY_REQ_HEADERS, [?CONTENT_JSON, {basic_auth, {"y", "y"}}]).
--define(SECURITY_OBJECT, {[
- {<<"members">>,{[{<<"roles">>,[<<"_admin">>, <<"_users">>]}]}},
- {<<"admins">>, {[{<<"roles">>,[<<"_admin">>]}]}}
-]}).
+-define(SECURITY_OBJECT,
+ {[
+ {<<"members">>, {[{<<"roles">>, [<<"_admin">>, <<"_users">>]}]}},
+ {<<"admins">>, {[{<<"roles">>, [<<"_admin">>]}]}}
+ ]}
+).
url() ->
Addr = config:get("httpd", "bind_address", "127.0.0.1"),
@@ -31,7 +33,9 @@ before_each(_) ->
R = test_request:put(url() ++ "/db?q=1&n=1&access=true", ?ADMIN_REQ_HEADERS, ""),
%?debugFmt("~nRequest: ~p~n", [R]),
{ok, 201, _, _} = R,
- {ok, _, _, _} = test_request:put(url() ++ "/db/_security", ?ADMIN_REQ_HEADERS, jiffy:encode(?SECURITY_OBJECT)),
+ {ok, _, _, _} = test_request:put(
+ url() ++ "/db/_security", ?ADMIN_REQ_HEADERS, jiffy:encode(?SECURITY_OBJECT)
+ ),
url().
after_each(_, Url) ->
@@ -43,10 +47,10 @@ after_each(_, Url) ->
before_all() ->
Couch = test_util:start_couch([chttpd, couch_replicator]),
Hashed = couch_passwords:hash_admin_password("a"),
- ok = config:set("admins", "a", binary_to_list(Hashed), _Persist=false),
- ok = config:set("couchdb", "uuid", "21ac467c1bc05e9d9e9d2d850bb1108f", _Persist=false),
- ok = config:set("log", "level", "debug", _Persist=false),
- ok = config:set("per_doc_access", "enabled", "true", _Persist=false),
+ ok = config:set("admins", "a", binary_to_list(Hashed), _Persist = false),
+ ok = config:set("couchdb", "uuid", "21ac467c1bc05e9d9e9d2d850bb1108f", _Persist = false),
+ ok = config:set("log", "level", "debug", _Persist = false),
+ ok = config:set("per_doc_access", "enabled", "true", _Persist = false),
% cleanup and setup
{ok, _, _, _} = test_request:delete(url() ++ "/db", ?ADMIN_REQ_HEADERS),
@@ -73,7 +77,6 @@ after_all(_) ->
access_test_() ->
Tests = [
-
% Server config
fun should_not_let_create_access_db_if_disabled/2,
@@ -109,7 +112,6 @@ access_test_() ->
fun should_let_admin_fetch_all_docs/2,
fun should_let_user_fetch_their_own_all_docs/2,
-
% _changes
fun should_let_admin_fetch_changes/2,
fun should_let_user_fetch_their_own_changes/2,
@@ -134,7 +136,6 @@ access_test_() ->
% _revs_diff for docs you don’t have access to
fun should_not_allow_user_to_revs_diff_other_docs/2
-
% TODO: create test db with role and not _users in _security.members
% and make sure a user in that group can access while a user not
% in that group cant
@@ -145,7 +146,8 @@ access_test_() ->
"Access tests",
{
setup,
- fun before_all/0, fun after_all/1,
+ fun before_all/0,
+ fun after_all/1,
[
make_test_cases(clustered, Tests)
]
@@ -159,7 +161,7 @@ make_test_cases(Mod, Funs) ->
}.
% Doc creation
- % http://127.0.0.1:64903/db/a?revs=true&open_revs=%5B%221-23202479633c2b380f79507a776743d5%22%5D&latest=true
+% http://127.0.0.1:64903/db/a?revs=true&open_revs=%5B%221-23202479633c2b380f79507a776743d5%22%5D&latest=true
% should_do_the_thing(_PortType, Url) ->
% ?_test(begin
@@ -172,9 +174,9 @@ make_test_cases(Mod, Funs) ->
%
should_not_let_create_access_db_if_disabled(_PortType, Url) ->
- ok = config:set("per_doc_access", "enabled", "false", _Persist=false),
+ ok = config:set("per_doc_access", "enabled", "false", _Persist = false),
{ok, Code, _, _} = test_request:put(url() ++ "/db?q=1&n=1&access=true", ?ADMIN_REQ_HEADERS, ""),
- ok = config:set("per_doc_access", "enabled", "true", _Persist=false),
+ ok = config:set("per_doc_access", "enabled", "true", _Persist = false),
?_assertEqual(400, Code).
should_not_let_anonymous_user_create_doc(_PortType, Url) ->
@@ -193,292 +195,489 @@ should_not_let_anonymous_user_create_doc(_PortType, Url) ->
?_assertEqual(401, Code).
should_let_admin_create_doc_with_access(_PortType, Url) ->
- {ok, Code, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
?_assertEqual(201, Code).
should_let_admin_create_doc_without_access(_PortType, Url) ->
- {ok, Code, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1}"),
+ {ok, Code, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1}"
+ ),
?_assertEqual(201, Code).
should_let_user_create_doc_for_themselves(_PortType, Url) ->
- {ok, Code, _, _} = test_request:put(Url ++ "/db/b",
- ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code, _, _} = test_request:put(
+ Url ++ "/db/b",
+ ?USERX_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
?_assertEqual(201, Code).
should_not_let_user_create_doc_for_someone_else(_PortType, Url) ->
- {ok, Code, _, _} = test_request:put(Url ++ "/db/c",
- ?USERY_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code, _, _} = test_request:put(
+ Url ++ "/db/c",
+ ?USERY_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
?_assertEqual(403, Code).
should_let_user_create_access_ddoc(_PortType, Url) ->
- {ok, Code, _, _} = test_request:put(Url ++ "/db/_design/dx",
- ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code, _, _} = test_request:put(
+ Url ++ "/db/_design/dx",
+ ?USERX_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
?_assertEqual(201, Code).
access_ddoc_should_have_no_effects(_PortType, Url) ->
?_test(begin
- Ddoc = "{ \"_access\":[\"x\"], \"validate_doc_update\": \"function(newDoc, oldDoc, userCtx) { throw({unauthorized: 'throw error'})}\", \"views\": { \"foo\": { \"map\": \"function(doc) { emit(doc._id) }\" } }, \"shows\": { \"boo\": \"function() {}\" }, \"lists\": { \"hoo\": \"function() {}\" }, \"update\": { \"goo\": \"function() {}\" }, \"filters\": { \"loo\": \"function() {}\" } }",
- {ok, Code, _, _} = test_request:put(Url ++ "/db/_design/dx",
- ?USERX_REQ_HEADERS, Ddoc),
+ Ddoc =
+ "{ \"_access\":[\"x\"], \"validate_doc_update\": \"function(newDoc, oldDoc, userCtx) { throw({unauthorized: 'throw error'})}\", \"views\": { \"foo\": { \"map\": \"function(doc) { emit(doc._id) }\" } }, \"shows\": { \"boo\": \"function() {}\" }, \"lists\": { \"hoo\": \"function() {}\" }, \"update\": { \"goo\": \"function() {}\" }, \"filters\": { \"loo\": \"function() {}\" } }",
+ {ok, Code, _, _} = test_request:put(
+ Url ++ "/db/_design/dx",
+ ?USERX_REQ_HEADERS,
+ Ddoc
+ ),
?assertEqual(201, Code),
- {ok, Code1, _, _} = test_request:put(Url ++ "/db/b",
- ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code1, _, _} = test_request:put(
+ Url ++ "/db/b",
+ ?USERX_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
?assertEqual(201, Code1),
- {ok, Code2, _, _} = test_request:get(Url ++ "/db/_design/dx/_view/foo",
- ?USERX_REQ_HEADERS),
+ {ok, Code2, _, _} = test_request:get(
+ Url ++ "/db/_design/dx/_view/foo",
+ ?USERX_REQ_HEADERS
+ ),
?assertEqual(404, Code2),
- {ok, Code3, _, _} = test_request:get(Url ++ "/db/_design/dx/_show/boo/b",
- ?USERX_REQ_HEADERS),
+ {ok, Code3, _, _} = test_request:get(
+ Url ++ "/db/_design/dx/_show/boo/b",
+ ?USERX_REQ_HEADERS
+ ),
?assertEqual(404, Code3),
- {ok, Code4, _, _} = test_request:get(Url ++ "/db/_design/dx/_list/hoo/foo",
- ?USERX_REQ_HEADERS),
+ {ok, Code4, _, _} = test_request:get(
+ Url ++ "/db/_design/dx/_list/hoo/foo",
+ ?USERX_REQ_HEADERS
+ ),
?assertEqual(404, Code4),
- {ok, Code5, _, _} = test_request:post(Url ++ "/db/_design/dx/_update/goo",
- ?USERX_REQ_HEADERS, ""),
+ {ok, Code5, _, _} = test_request:post(
+ Url ++ "/db/_design/dx/_update/goo",
+ ?USERX_REQ_HEADERS,
+ ""
+ ),
?assertEqual(404, Code5),
- {ok, Code6, _, _} = test_request:get(Url ++ "/db/_changes?filter=dx/loo",
- ?USERX_REQ_HEADERS),
+ {ok, Code6, _, _} = test_request:get(
+ Url ++ "/db/_changes?filter=dx/loo",
+ ?USERX_REQ_HEADERS
+ ),
?assertEqual(404, Code6),
- {ok, Code7, _, _} = test_request:get(Url ++ "/db/_changes?filter=_view&view=dx/foo",
- ?USERX_REQ_HEADERS),
+ {ok, Code7, _, _} = test_request:get(
+ Url ++ "/db/_changes?filter=_view&view=dx/foo",
+ ?USERX_REQ_HEADERS
+ ),
?assertEqual(404, Code7)
end).
% Doc updates
users_with_access_can_update_doc(_PortType, Url) ->
- {ok, _, _, Body} = test_request:put(Url ++ "/db/b",
- ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, _, _, Body} = test_request:put(
+ Url ++ "/db/b",
+ ?USERX_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
{Json} = jiffy:decode(Body),
Rev = couch_util:get_value(<<"rev">>, Json),
- {ok, Code, _, _} = test_request:put(Url ++ "/db/b",
+ {ok, Code, _, _} = test_request:put(
+ Url ++ "/db/b",
?USERX_REQ_HEADERS,
- "{\"a\":2,\"_access\":[\"x\"],\"_rev\":\"" ++ binary_to_list(Rev) ++ "\"}"),
+ "{\"a\":2,\"_access\":[\"x\"],\"_rev\":\"" ++ binary_to_list(Rev) ++ "\"}"
+ ),
?_assertEqual(201, Code).
users_without_access_can_not_update_doc(_PortType, Url) ->
- {ok, _, _, Body} = test_request:put(Url ++ "/db/b",
- ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, _, _, Body} = test_request:put(
+ Url ++ "/db/b",
+ ?USERX_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
{Json} = jiffy:decode(Body),
Rev = couch_util:get_value(<<"rev">>, Json),
- {ok, Code, _, _} = test_request:put(Url ++ "/db/b",
+ {ok, Code, _, _} = test_request:put(
+ Url ++ "/db/b",
?USERY_REQ_HEADERS,
- "{\"a\":2,\"_access\":[\"y\"],\"_rev\":\"" ++ binary_to_list(Rev) ++ "\"}"),
+ "{\"a\":2,\"_access\":[\"y\"],\"_rev\":\"" ++ binary_to_list(Rev) ++ "\"}"
+ ),
?_assertEqual(403, Code).
users_with_access_can_not_change_access(_PortType, Url) ->
- {ok, _, _, Body} = test_request:put(Url ++ "/db/b",
- ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, _, _, Body} = test_request:put(
+ Url ++ "/db/b",
+ ?USERX_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
{Json} = jiffy:decode(Body),
Rev = couch_util:get_value(<<"rev">>, Json),
- {ok, Code, _, _} = test_request:put(Url ++ "/db/b",
+ {ok, Code, _, _} = test_request:put(
+ Url ++ "/db/b",
?USERX_REQ_HEADERS,
- "{\"a\":2,\"_access\":[\"y\"],\"_rev\":\"" ++ binary_to_list(Rev) ++ "\"}"),
+ "{\"a\":2,\"_access\":[\"y\"],\"_rev\":\"" ++ binary_to_list(Rev) ++ "\"}"
+ ),
?_assertEqual(403, Code).
users_with_access_can_not_remove_access(_PortType, Url) ->
- {ok, _, _, Body} = test_request:put(Url ++ "/db/b",
- ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, _, _, Body} = test_request:put(
+ Url ++ "/db/b",
+ ?USERX_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
{Json} = jiffy:decode(Body),
Rev = couch_util:get_value(<<"rev">>, Json),
- {ok, Code, _, _} = test_request:put(Url ++ "/db/b",
+ {ok, Code, _, _} = test_request:put(
+ Url ++ "/db/b",
?USERX_REQ_HEADERS,
- "{\"a\":2,\"_rev\":\"" ++ binary_to_list(Rev) ++ "\"}"),
+ "{\"a\":2,\"_rev\":\"" ++ binary_to_list(Rev) ++ "\"}"
+ ),
?_assertEqual(403, Code).
% Doc reads
should_let_admin_read_doc_with_access(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
- ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, Code, _, _} = test_request:get(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?USERX_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, Code, _, _} = test_request:get(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS
+ ),
?_assertEqual(200, Code).
user_with_access_can_read_doc(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, Code, _, _} = test_request:get(Url ++ "/db/a",
- ?USERX_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, Code, _, _} = test_request:get(
+ Url ++ "/db/a",
+ ?USERX_REQ_HEADERS
+ ),
?_assertEqual(200, Code).
user_with_access_can_not_read_conflicted_doc(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"_id\":\"f1\",\"a\":1,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a?new_edits=false",
- ?ADMIN_REQ_HEADERS, "{\"_id\":\"f1\",\"_rev\":\"7-XYZ\",\"a\":1,\"_access\":[\"x\"]}"),
- {ok, Code, _, _} = test_request:get(Url ++ "/db/a",
- ?USERX_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"_id\":\"f1\",\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a?new_edits=false",
+ ?ADMIN_REQ_HEADERS,
+ "{\"_id\":\"f1\",\"_rev\":\"7-XYZ\",\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, Code, _, _} = test_request:get(
+ Url ++ "/db/a",
+ ?USERX_REQ_HEADERS
+ ),
?_assertEqual(403, Code).
admin_with_access_can_read_conflicted_doc(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"_id\":\"a\",\"a\":1,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a?new_edits=false",
- ?ADMIN_REQ_HEADERS, "{\"_id\":\"a\",\"_rev\":\"7-XYZ\",\"a\":1,\"_access\":[\"x\"]}"),
- {ok, Code, _, _} = test_request:get(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"_id\":\"a\",\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a?new_edits=false",
+ ?ADMIN_REQ_HEADERS,
+ "{\"_id\":\"a\",\"_rev\":\"7-XYZ\",\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, Code, _, _} = test_request:get(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS
+ ),
?_assertEqual(200, Code).
user_without_access_can_not_read_doc(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, Code, _, _} = test_request:get(Url ++ "/db/a",
- ?USERY_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, Code, _, _} = test_request:get(
+ Url ++ "/db/a",
+ ?USERY_REQ_HEADERS
+ ),
?_assertEqual(403, Code).
user_can_not_read_doc_without_access(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1}"),
- {ok, Code, _, _} = test_request:get(Url ++ "/db/a",
- ?USERX_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1}"
+ ),
+ {ok, Code, _, _} = test_request:get(
+ Url ++ "/db/a",
+ ?USERX_REQ_HEADERS
+ ),
?_assertEqual(403, Code).
% Doc deletes
should_let_admin_delete_doc_with_access(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
- ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, Code, _, _} = test_request:delete(Url ++ "/db/a?rev=1-23202479633c2b380f79507a776743d5",
- ?ADMIN_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?USERX_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, Code, _, _} = test_request:delete(
+ Url ++ "/db/a?rev=1-23202479633c2b380f79507a776743d5",
+ ?ADMIN_REQ_HEADERS
+ ),
?_assertEqual(200, Code).
should_let_user_delete_doc_for_themselves(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
- ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:get(Url ++ "/db/a",
- ?USERX_REQ_HEADERS),
- {ok, Code, _, _} = test_request:delete(Url ++ "/db/a?rev=1-23202479633c2b380f79507a776743d5",
- ?USERX_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?USERX_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:get(
+ Url ++ "/db/a",
+ ?USERX_REQ_HEADERS
+ ),
+ {ok, Code, _, _} = test_request:delete(
+ Url ++ "/db/a?rev=1-23202479633c2b380f79507a776743d5",
+ ?USERX_REQ_HEADERS
+ ),
?_assertEqual(200, Code).
should_not_let_user_delete_doc_for_someone_else(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
- ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, Code, _, _} = test_request:delete(Url ++ "/db/a?rev=1-23202479633c2b380f79507a776743d5",
- ?USERY_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?USERX_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, Code, _, _} = test_request:delete(
+ Url ++ "/db/a?rev=1-23202479633c2b380f79507a776743d5",
+ ?USERY_REQ_HEADERS
+ ),
?_assertEqual(403, Code).
% _all_docs with include_docs
should_let_admin_fetch_all_docs(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/b",
- ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/c",
- ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/d",
- ?ADMIN_REQ_HEADERS, "{\"d\":4,\"_access\":[\"y\"]}"),
- {ok, 200, _, Body} = test_request:get(Url ++ "/db/_all_docs?include_docs=true",
- ?ADMIN_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/b",
+ ?ADMIN_REQ_HEADERS,
+ "{\"b\":2,\"_access\":[\"x\"]}"
+ ),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/c",
+ ?ADMIN_REQ_HEADERS,
+ "{\"c\":3,\"_access\":[\"y\"]}"
+ ),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/d",
+ ?ADMIN_REQ_HEADERS,
+ "{\"d\":4,\"_access\":[\"y\"]}"
+ ),
+ {ok, 200, _, Body} = test_request:get(
+ Url ++ "/db/_all_docs?include_docs=true",
+ ?ADMIN_REQ_HEADERS
+ ),
{Json} = jiffy:decode(Body),
?_assertEqual(4, proplists:get_value(<<"total_rows">>, Json)).
should_let_user_fetch_their_own_all_docs(_PortType, Url) ->
?_test(begin
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/b",
- ?USERX_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/c",
- ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/d",
- ?USERY_REQ_HEADERS, "{\"d\":4,\"_access\":[\"y\"]}"),
- {ok, 200, _, Body} = test_request:get(Url ++ "/db/_all_docs?include_docs=true",
- ?USERX_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/b",
+ ?USERX_REQ_HEADERS,
+ "{\"b\":2,\"_access\":[\"x\"]}"
+ ),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/c",
+ ?ADMIN_REQ_HEADERS,
+ "{\"c\":3,\"_access\":[\"y\"]}"
+ ),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/d",
+ ?USERY_REQ_HEADERS,
+ "{\"d\":4,\"_access\":[\"y\"]}"
+ ),
+ {ok, 200, _, Body} = test_request:get(
+ Url ++ "/db/_all_docs?include_docs=true",
+ ?USERX_REQ_HEADERS
+ ),
{Json} = jiffy:decode(Body),
Rows = proplists:get_value(<<"rows">>, Json),
- ?assertEqual([{[{<<"id">>,<<"a">>},
- {<<"key">>,<<"a">>},
- {<<"value">>,<<"1-23202479633c2b380f79507a776743d5">>},
- {<<"doc">>,
- {[{<<"_id">>,<<"a">>},
- {<<"_rev">>,<<"1-23202479633c2b380f79507a776743d5">>},
- {<<"a">>,1},
- {<<"_access">>,[<<"x">>]}]}}]},
- {[{<<"id">>,<<"b">>},
- {<<"key">>,<<"b">>},
- {<<"value">>,<<"1-d33fb05384fa65a8081da2046595de0f">>},
- {<<"doc">>,
- {[{<<"_id">>,<<"b">>},
- {<<"_rev">>,<<"1-d33fb05384fa65a8081da2046595de0f">>},
- {<<"b">>,2},
- {<<"_access">>,[<<"x">>]}]}}]}], Rows),
+ ?assertEqual(
+ [
+ {[
+ {<<"id">>, <<"a">>},
+ {<<"key">>, <<"a">>},
+ {<<"value">>, <<"1-23202479633c2b380f79507a776743d5">>},
+ {<<"doc">>,
+ {[
+ {<<"_id">>, <<"a">>},
+ {<<"_rev">>, <<"1-23202479633c2b380f79507a776743d5">>},
+ {<<"a">>, 1},
+ {<<"_access">>, [<<"x">>]}
+ ]}}
+ ]},
+ {[
+ {<<"id">>, <<"b">>},
+ {<<"key">>, <<"b">>},
+ {<<"value">>, <<"1-d33fb05384fa65a8081da2046595de0f">>},
+ {<<"doc">>,
+ {[
+ {<<"_id">>, <<"b">>},
+ {<<"_rev">>, <<"1-d33fb05384fa65a8081da2046595de0f">>},
+ {<<"b">>, 2},
+ {<<"_access">>, [<<"x">>]}
+ ]}}
+ ]}
+ ],
+ Rows
+ ),
?assertEqual(2, length(Rows)),
?assertEqual(4, proplists:get_value(<<"total_rows">>, Json)),
- {ok, 200, _, Body1} = test_request:get(Url ++ "/db/_all_docs?include_docs=true",
- ?USERY_REQ_HEADERS),
+ {ok, 200, _, Body1} = test_request:get(
+ Url ++ "/db/_all_docs?include_docs=true",
+ ?USERY_REQ_HEADERS
+ ),
{Json1} = jiffy:decode(Body1),
- ?assertEqual( [{<<"total_rows">>,4},
- {<<"offset">>,2},
- {<<"rows">>,
- [{[{<<"id">>,<<"c">>},
- {<<"key">>,<<"c">>},
- {<<"value">>,<<"1-92aef5b0e4a3f4db0aba1320869bc95d">>},
- {<<"doc">>,
- {[{<<"_id">>,<<"c">>},
- {<<"_rev">>,<<"1-92aef5b0e4a3f4db0aba1320869bc95d">>},
- {<<"c">>,3},
- {<<"_access">>,[<<"y">>]}]}}]},
- {[{<<"id">>,<<"d">>},
- {<<"key">>,<<"d">>},
- {<<"value">>,<<"1-ae984f6550038b1ed1565ac4b6cd8c5d">>},
- {<<"doc">>,
- {[{<<"_id">>,<<"d">>},
- {<<"_rev">>,<<"1-ae984f6550038b1ed1565ac4b6cd8c5d">>},
- {<<"d">>,4},
- {<<"_access">>,[<<"y">>]}]}}]}]}], Json1)
+ ?assertEqual(
+ [
+ {<<"total_rows">>, 4},
+ {<<"offset">>, 2},
+ {<<"rows">>, [
+ {[
+ {<<"id">>, <<"c">>},
+ {<<"key">>, <<"c">>},
+ {<<"value">>, <<"1-92aef5b0e4a3f4db0aba1320869bc95d">>},
+ {<<"doc">>,
+ {[
+ {<<"_id">>, <<"c">>},
+ {<<"_rev">>, <<"1-92aef5b0e4a3f4db0aba1320869bc95d">>},
+ {<<"c">>, 3},
+ {<<"_access">>, [<<"y">>]}
+ ]}}
+ ]},
+ {[
+ {<<"id">>, <<"d">>},
+ {<<"key">>, <<"d">>},
+ {<<"value">>, <<"1-ae984f6550038b1ed1565ac4b6cd8c5d">>},
+ {<<"doc">>,
+ {[
+ {<<"_id">>, <<"d">>},
+ {<<"_rev">>, <<"1-ae984f6550038b1ed1565ac4b6cd8c5d">>},
+ {<<"d">>, 4},
+ {<<"_access">>, [<<"y">>]}
+ ]}}
+ ]}
+ ]}
+ ],
+ Json1
+ )
end).
-
% _changes
should_let_admin_fetch_changes(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/b",
- ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/c",
- ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/d",
- ?ADMIN_REQ_HEADERS, "{\"d\":4,\"_access\":[\"y\"]}"),
- {ok, 200, _, Body} = test_request:get(Url ++ "/db/_changes",
- ?ADMIN_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/b",
+ ?ADMIN_REQ_HEADERS,
+ "{\"b\":2,\"_access\":[\"x\"]}"
+ ),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/c",
+ ?ADMIN_REQ_HEADERS,
+ "{\"c\":3,\"_access\":[\"y\"]}"
+ ),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/d",
+ ?ADMIN_REQ_HEADERS,
+ "{\"d\":4,\"_access\":[\"y\"]}"
+ ),
+ {ok, 200, _, Body} = test_request:get(
+ Url ++ "/db/_changes",
+ ?ADMIN_REQ_HEADERS
+ ),
{Json} = jiffy:decode(Body),
AmountOfDocs = length(proplists:get_value(<<"results">>, Json)),
?_assertEqual(4, AmountOfDocs).
should_let_user_fetch_their_own_changes(_PortType, Url) ->
?_test(begin
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/b",
- ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/c",
- ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/d",
- ?ADMIN_REQ_HEADERS, "{\"d\":4,\"_access\":[\"y\"]}"),
- {ok, 200, _, Body} = test_request:get(Url ++ "/db/_changes",
- ?USERX_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/b",
+ ?ADMIN_REQ_HEADERS,
+ "{\"b\":2,\"_access\":[\"x\"]}"
+ ),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/c",
+ ?ADMIN_REQ_HEADERS,
+ "{\"c\":3,\"_access\":[\"y\"]}"
+ ),
+ {ok, 201, _, _} = test_request:put(
+ Url ++ "/db/d",
+ ?ADMIN_REQ_HEADERS,
+ "{\"d\":4,\"_access\":[\"y\"]}"
+ ),
+ {ok, 200, _, Body} = test_request:get(
+ Url ++ "/db/_changes",
+ ?USERX_REQ_HEADERS
+ ),
{Json} = jiffy:decode(Body),
- ?assertMatch([{<<"results">>,
- [{[{<<"seq">>,
- <<"2-", _/binary>>},
- {<<"id">>,<<"a">>},
- {<<"changes">>,
- [{[{<<"rev">>,<<"1-23202479633c2b380f79507a776743d5">>}]}]}]},
- {[{<<"seq">>,
- <<"3-", _/binary>>},
- {<<"id">>,<<"b">>},
- {<<"changes">>,
- [{[{<<"rev">>,<<"1-d33fb05384fa65a8081da2046595de0f">>}]}]}]}]},
- {<<"last_seq">>,
- <<"3-", _/binary>>},
- {<<"pending">>,2}], Json),
+ ?assertMatch(
+ [
+ {<<"results">>, [
+ {[
+ {<<"seq">>, <<"2-", _/binary>>},
+ {<<"id">>, <<"a">>},
+ {<<"changes">>, [{[{<<"rev">>, <<"1-23202479633c2b380f79507a776743d5">>}]}]}
+ ]},
+ {[
+ {<<"seq">>, <<"3-", _/binary>>},
+ {<<"id">>, <<"b">>},
+ {<<"changes">>, [{[{<<"rev">>, <<"1-d33fb05384fa65a8081da2046595de0f">>}]}]}
+ ]}
+ ]},
+ {<<"last_seq">>, <<"3-", _/binary>>},
+ {<<"pending">>, 2}
+ ],
+ Json
+ ),
AmountOfDocs = length(proplists:get_value(<<"results">>, Json)),
?assertEqual(2, AmountOfDocs)
end).
@@ -487,38 +686,58 @@ should_let_user_fetch_their_own_changes(_PortType, Url) ->
should_not_allow_admin_access_ddoc_view_request(_PortType, Url) ->
DDoc = "{\"a\":1,\"_access\":[\"x\"],\"views\":{\"foo\":{\"map\":\"function() {}\"}}}",
- {ok, Code, _, _} = test_request:put(Url ++ "/db/_design/a",
- ?ADMIN_REQ_HEADERS, DDoc),
+ {ok, Code, _, _} = test_request:put(
+ Url ++ "/db/_design/a",
+ ?ADMIN_REQ_HEADERS,
+ DDoc
+ ),
?assertEqual(201, Code),
- {ok, Code1, _, _} = test_request:get(Url ++ "/db/_design/a/_view/foo",
- ?ADMIN_REQ_HEADERS),
+ {ok, Code1, _, _} = test_request:get(
+ Url ++ "/db/_design/a/_view/foo",
+ ?ADMIN_REQ_HEADERS
+ ),
?_assertEqual(404, Code1).
should_not_allow_user_access_ddoc_view_request(_PortType, Url) ->
DDoc = "{\"a\":1,\"_access\":[\"x\"],\"views\":{\"foo\":{\"map\":\"function() {}\"}}}",
- {ok, Code, _, _} = test_request:put(Url ++ "/db/_design/a",
- ?ADMIN_REQ_HEADERS, DDoc),
+ {ok, Code, _, _} = test_request:put(
+ Url ++ "/db/_design/a",
+ ?ADMIN_REQ_HEADERS,
+ DDoc
+ ),
?assertEqual(201, Code),
- {ok, Code1, _, _} = test_request:get(Url ++ "/db/_design/a/_view/foo",
- ?USERX_REQ_HEADERS),
+ {ok, Code1, _, _} = test_request:get(
+ Url ++ "/db/_design/a/_view/foo",
+ ?USERX_REQ_HEADERS
+ ),
?_assertEqual(404, Code1).
should_allow_admin_users_access_ddoc_view_request(_PortType, Url) ->
DDoc = "{\"a\":1,\"_access\":[\"_users\"],\"views\":{\"foo\":{\"map\":\"function() {}\"}}}",
- {ok, Code, _, _} = test_request:put(Url ++ "/db/_design/a",
- ?ADMIN_REQ_HEADERS, DDoc),
+ {ok, Code, _, _} = test_request:put(
+ Url ++ "/db/_design/a",
+ ?ADMIN_REQ_HEADERS,
+ DDoc
+ ),
?assertEqual(201, Code),
- {ok, Code1, _, _} = test_request:get(Url ++ "/db/_design/a/_view/foo",
- ?ADMIN_REQ_HEADERS),
+ {ok, Code1, _, _} = test_request:get(
+ Url ++ "/db/_design/a/_view/foo",
+ ?ADMIN_REQ_HEADERS
+ ),
?_assertEqual(200, Code1).
should_allow_user_users_access_ddoc_view_request(_PortType, Url) ->
DDoc = "{\"a\":1,\"_access\":[\"_users\"],\"views\":{\"foo\":{\"map\":\"function() {}\"}}}",
- {ok, Code, _, _} = test_request:put(Url ++ "/db/_design/a",
- ?ADMIN_REQ_HEADERS, DDoc),
+ {ok, Code, _, _} = test_request:put(
+ Url ++ "/db/_design/a",
+ ?ADMIN_REQ_HEADERS,
+ DDoc
+ ),
?assertEqual(201, Code),
- {ok, Code1, _, _} = test_request:get(Url ++ "/db/_design/a/_view/foo",
- ?USERX_REQ_HEADERS),
+ {ok, Code1, _, _} = test_request:get(
+ Url ++ "/db/_design/a/_view/foo",
+ ?USERX_REQ_HEADERS
+ ),
?_assertEqual(200, Code1).
% replication
@@ -526,28 +745,47 @@ should_allow_user_users_access_ddoc_view_request(_PortType, Url) ->
should_allow_admin_to_replicate_from_access_to_access(_PortType, Url) ->
?_test(begin
% create target db
- {ok, 201, _, _} = test_request:put(url() ++ "/db2?q=1&n=1&access=true",
- ?ADMIN_REQ_HEADERS, ""),
+ {ok, 201, _, _} = test_request:put(
+ url() ++ "/db2?q=1&n=1&access=true",
+ ?ADMIN_REQ_HEADERS,
+ ""
+ ),
% set target db security
- {ok, _, _, _} = test_request:put(url() ++ "/db2/_security",
- ?ADMIN_REQ_HEADERS, jiffy:encode(?SECURITY_OBJECT)),
+ {ok, _, _, _} = test_request:put(
+ url() ++ "/db2/_security",
+ ?ADMIN_REQ_HEADERS,
+ jiffy:encode(?SECURITY_OBJECT)
+ ),
% create source docs
- {ok, _, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db/b",
- ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db/c",
- ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"x\"]}"),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db/b",
+ ?ADMIN_REQ_HEADERS,
+ "{\"b\":2,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db/c",
+ ?ADMIN_REQ_HEADERS,
+ "{\"c\":3,\"_access\":[\"x\"]}"
+ ),
% replicate
AdminUrl = string:replace(Url, "http://", "http://a:a@"),
- EJRequestBody = {[
- {<<"source">>, list_to_binary(AdminUrl ++ "/db")},
- {<<"target">>, list_to_binary(AdminUrl ++ "/db2")}
- ]},
- {ok, ResponseCode, _, ResponseBody} = test_request:post(Url ++ "/_replicate",
- ?ADMIN_REQ_HEADERS, jiffy:encode(EJRequestBody)),
+ EJRequestBody =
+ {[
+ {<<"source">>, list_to_binary(AdminUrl ++ "/db")},
+ {<<"target">>, list_to_binary(AdminUrl ++ "/db2")}
+ ]},
+ {ok, ResponseCode, _, ResponseBody} = test_request:post(
+ Url ++ "/_replicate",
+ ?ADMIN_REQ_HEADERS,
+ jiffy:encode(EJRequestBody)
+ ),
% assert replication status
{EJResponseBody} = jiffy:decode(ResponseBody),
@@ -560,16 +798,18 @@ should_allow_admin_to_replicate_from_access_to_access(_PortType, Url) ->
DocsReard = couch_util:get_value(<<"docs_read">>, History),
DocsWritten = couch_util:get_value(<<"docs_written">>, History),
DocWriteFailures = couch_util:get_value(<<"doc_write_failures">>, History),
-
+
?assertEqual(3, MissingChecked),
?assertEqual(3, MissingFound),
?assertEqual(3, DocsReard),
?assertEqual(3, DocsWritten),
?assertEqual(0, DocWriteFailures),
-
+
% assert docs in target db
- {ok, 200, _, ADBody} = test_request:get(Url ++ "/db2/_all_docs?include_docs=true",
- ?ADMIN_REQ_HEADERS),
+ {ok, 200, _, ADBody} = test_request:get(
+ Url ++ "/db2/_all_docs?include_docs=true",
+ ?ADMIN_REQ_HEADERS
+ ),
{Json} = jiffy:decode(ADBody),
?assertEqual(3, proplists:get_value(<<"total_rows">>, Json))
end).
@@ -577,28 +817,47 @@ should_allow_admin_to_replicate_from_access_to_access(_PortType, Url) ->
should_allow_admin_to_replicate_from_no_access_to_access(_PortType, Url) ->
?_test(begin
% create target db
- {ok, 201, _, _} = test_request:put(url() ++ "/db2?q=1&n=1",
- ?ADMIN_REQ_HEADERS, ""),
+ {ok, 201, _, _} = test_request:put(
+ url() ++ "/db2?q=1&n=1",
+ ?ADMIN_REQ_HEADERS,
+ ""
+ ),
% set target db security
- {ok, _, _, _} = test_request:put(url() ++ "/db2/_security",
- ?ADMIN_REQ_HEADERS, jiffy:encode(?SECURITY_OBJECT)),
+ {ok, _, _, _} = test_request:put(
+ url() ++ "/db2/_security",
+ ?ADMIN_REQ_HEADERS,
+ jiffy:encode(?SECURITY_OBJECT)
+ ),
% create source docs
- {ok, _, _, _} = test_request:put(Url ++ "/db2/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db2/b",
- ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db2/c",
- ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"x\"]}"),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db2/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db2/b",
+ ?ADMIN_REQ_HEADERS,
+ "{\"b\":2,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db2/c",
+ ?ADMIN_REQ_HEADERS,
+ "{\"c\":3,\"_access\":[\"x\"]}"
+ ),
% replicate
AdminUrl = string:replace(Url, "http://", "http://a:a@"),
- EJRequestBody = {[
- {<<"source">>, list_to_binary(AdminUrl ++ "/db2")},
- {<<"target">>, list_to_binary(AdminUrl ++ "/db")}
- ]},
- {ok, ResponseCode, _, ResponseBody} = test_request:post(Url ++ "/_replicate",
- ?ADMIN_REQ_HEADERS, jiffy:encode(EJRequestBody)),
+ EJRequestBody =
+ {[
+ {<<"source">>, list_to_binary(AdminUrl ++ "/db2")},
+ {<<"target">>, list_to_binary(AdminUrl ++ "/db")}
+ ]},
+ {ok, ResponseCode, _, ResponseBody} = test_request:post(
+ Url ++ "/_replicate",
+ ?ADMIN_REQ_HEADERS,
+ jiffy:encode(EJRequestBody)
+ ),
% assert replication status
{EJResponseBody} = jiffy:decode(ResponseBody),
@@ -611,16 +870,18 @@ should_allow_admin_to_replicate_from_no_access_to_access(_PortType, Url) ->
DocsReard = couch_util:get_value(<<"docs_read">>, History),
DocsWritten = couch_util:get_value(<<"docs_written">>, History),
DocWriteFailures = couch_util:get_value(<<"doc_write_failures">>, History),
-
+
?assertEqual(3, MissingChecked),
?assertEqual(3, MissingFound),
?assertEqual(3, DocsReard),
?assertEqual(3, DocsWritten),
?assertEqual(0, DocWriteFailures),
-
+
% assert docs in target db
- {ok, 200, _, ADBody} = test_request:get(Url ++ "/db/_all_docs?include_docs=true",
- ?ADMIN_REQ_HEADERS),
+ {ok, 200, _, ADBody} = test_request:get(
+ Url ++ "/db/_all_docs?include_docs=true",
+ ?ADMIN_REQ_HEADERS
+ ),
{Json} = jiffy:decode(ADBody),
?assertEqual(3, proplists:get_value(<<"total_rows">>, Json))
end).
@@ -628,28 +889,47 @@ should_allow_admin_to_replicate_from_no_access_to_access(_PortType, Url) ->
should_allow_admin_to_replicate_from_access_to_no_access(_PortType, Url) ->
?_test(begin
% create target db
- {ok, 201, _, _} = test_request:put(url() ++ "/db2?q=1&n=1",
- ?ADMIN_REQ_HEADERS, ""),
+ {ok, 201, _, _} = test_request:put(
+ url() ++ "/db2?q=1&n=1",
+ ?ADMIN_REQ_HEADERS,
+ ""
+ ),
% set target db security
- {ok, _, _, _} = test_request:put(url() ++ "/db2/_security",
- ?ADMIN_REQ_HEADERS, jiffy:encode(?SECURITY_OBJECT)),
+ {ok, _, _, _} = test_request:put(
+ url() ++ "/db2/_security",
+ ?ADMIN_REQ_HEADERS,
+ jiffy:encode(?SECURITY_OBJECT)
+ ),
% create source docs
- {ok, _, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db/b",
- ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db/c",
- ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"x\"]}"),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db/b",
+ ?ADMIN_REQ_HEADERS,
+ "{\"b\":2,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db/c",
+ ?ADMIN_REQ_HEADERS,
+ "{\"c\":3,\"_access\":[\"x\"]}"
+ ),
% replicate
AdminUrl = string:replace(Url, "http://", "http://a:a@"),
- EJRequestBody = {[
- {<<"source">>, list_to_binary(AdminUrl ++ "/db")},
- {<<"target">>, list_to_binary(AdminUrl ++ "/db2")}
- ]},
- {ok, ResponseCode, _, ResponseBody} = test_request:post(Url ++ "/_replicate",
- ?ADMIN_REQ_HEADERS, jiffy:encode(EJRequestBody)),
+ EJRequestBody =
+ {[
+ {<<"source">>, list_to_binary(AdminUrl ++ "/db")},
+ {<<"target">>, list_to_binary(AdminUrl ++ "/db2")}
+ ]},
+ {ok, ResponseCode, _, ResponseBody} = test_request:post(
+ Url ++ "/_replicate",
+ ?ADMIN_REQ_HEADERS,
+ jiffy:encode(EJRequestBody)
+ ),
% assert replication status
{EJResponseBody} = jiffy:decode(ResponseBody),
@@ -662,16 +942,18 @@ should_allow_admin_to_replicate_from_access_to_no_access(_PortType, Url) ->
DocsReard = couch_util:get_value(<<"docs_read">>, History),
DocsWritten = couch_util:get_value(<<"docs_written">>, History),
DocWriteFailures = couch_util:get_value(<<"doc_write_failures">>, History),
-
+
?assertEqual(3, MissingChecked),
?assertEqual(3, MissingFound),
?assertEqual(3, DocsReard),
?assertEqual(3, DocsWritten),
?assertEqual(0, DocWriteFailures),
-
+
% assert docs in target db
- {ok, 200, _, ADBody} = test_request:get(Url ++ "/db2/_all_docs?include_docs=true",
- ?ADMIN_REQ_HEADERS),
+ {ok, 200, _, ADBody} = test_request:get(
+ Url ++ "/db2/_all_docs?include_docs=true",
+ ?ADMIN_REQ_HEADERS
+ ),
{Json} = jiffy:decode(ADBody),
?assertEqual(3, proplists:get_value(<<"total_rows">>, Json))
end).
@@ -679,34 +961,59 @@ should_allow_admin_to_replicate_from_access_to_no_access(_PortType, Url) ->
should_allow_admin_to_replicate_from_no_access_to_no_access(_PortType, Url) ->
?_test(begin
% create source and target dbs
- {ok, 201, _, _} = test_request:put(url() ++ "/db2?q=1&n=1",
- ?ADMIN_REQ_HEADERS, ""),
+ {ok, 201, _, _} = test_request:put(
+ url() ++ "/db2?q=1&n=1",
+ ?ADMIN_REQ_HEADERS,
+ ""
+ ),
% set target db security
- {ok, _, _, _} = test_request:put(url() ++ "/db2/_security",
- ?ADMIN_REQ_HEADERS, jiffy:encode(?SECURITY_OBJECT)),
-
- {ok, 201, _, _} = test_request:put(url() ++ "/db3?q=1&n=1",
- ?ADMIN_REQ_HEADERS, ""),
+ {ok, _, _, _} = test_request:put(
+ url() ++ "/db2/_security",
+ ?ADMIN_REQ_HEADERS,
+ jiffy:encode(?SECURITY_OBJECT)
+ ),
+
+ {ok, 201, _, _} = test_request:put(
+ url() ++ "/db3?q=1&n=1",
+ ?ADMIN_REQ_HEADERS,
+ ""
+ ),
% set target db security
- {ok, _, _, _} = test_request:put(url() ++ "/db3/_security",
- ?ADMIN_REQ_HEADERS, jiffy:encode(?SECURITY_OBJECT)),
+ {ok, _, _, _} = test_request:put(
+ url() ++ "/db3/_security",
+ ?ADMIN_REQ_HEADERS,
+ jiffy:encode(?SECURITY_OBJECT)
+ ),
% create source docs
- {ok, _, _, _} = test_request:put(Url ++ "/db2/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db2/b",
- ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db2/c",
- ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"x\"]}"),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db2/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db2/b",
+ ?ADMIN_REQ_HEADERS,
+ "{\"b\":2,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db2/c",
+ ?ADMIN_REQ_HEADERS,
+ "{\"c\":3,\"_access\":[\"x\"]}"
+ ),
% replicate
AdminUrl = string:replace(Url, "http://", "http://a:a@"),
- EJRequestBody = {[
- {<<"source">>, list_to_binary(AdminUrl ++ "/db2")},
- {<<"target">>, list_to_binary(AdminUrl ++ "/db3")}
- ]},
- {ok, ResponseCode, _, ResponseBody} = test_request:post(Url ++ "/_replicate",
- ?ADMIN_REQ_HEADERS, jiffy:encode(EJRequestBody)),
+ EJRequestBody =
+ {[
+ {<<"source">>, list_to_binary(AdminUrl ++ "/db2")},
+ {<<"target">>, list_to_binary(AdminUrl ++ "/db3")}
+ ]},
+ {ok, ResponseCode, _, ResponseBody} = test_request:post(
+ Url ++ "/_replicate",
+ ?ADMIN_REQ_HEADERS,
+ jiffy:encode(EJRequestBody)
+ ),
% assert replication status
{EJResponseBody} = jiffy:decode(ResponseBody),
@@ -719,16 +1026,18 @@ should_allow_admin_to_replicate_from_no_access_to_no_access(_PortType, Url) ->
DocsReard = couch_util:get_value(<<"docs_read">>, History),
DocsWritten = couch_util:get_value(<<"docs_written">>, History),
DocWriteFailures = couch_util:get_value(<<"doc_write_failures">>, History),
-
+
?assertEqual(3, MissingChecked),
?assertEqual(3, MissingFound),
?assertEqual(3, DocsReard),
?assertEqual(3, DocsWritten),
?assertEqual(0, DocWriteFailures),
-
+
% assert docs in target db
- {ok, 200, _, ADBody} = test_request:get(Url ++ "/db3/_all_docs?include_docs=true",
- ?ADMIN_REQ_HEADERS),
+ {ok, 200, _, ADBody} = test_request:get(
+ Url ++ "/db3/_all_docs?include_docs=true",
+ ?ADMIN_REQ_HEADERS
+ ),
{Json} = jiffy:decode(ADBody),
?assertEqual(3, proplists:get_value(<<"total_rows">>, Json))
end).
@@ -736,28 +1045,47 @@ should_allow_admin_to_replicate_from_no_access_to_no_access(_PortType, Url) ->
should_allow_user_to_replicate_from_access_to_access(_PortType, Url) ->
?_test(begin
% create source and target dbs
- {ok, 201, _, _} = test_request:put(url() ++ "/db2?q=1&n=1&access=true",
- ?ADMIN_REQ_HEADERS, ""),
+ {ok, 201, _, _} = test_request:put(
+ url() ++ "/db2?q=1&n=1&access=true",
+ ?ADMIN_REQ_HEADERS,
+ ""
+ ),
% set target db security
- {ok, _, _, _} = test_request:put(url() ++ "/db2/_security",
- ?ADMIN_REQ_HEADERS, jiffy:encode(?SECURITY_OBJECT)),
+ {ok, _, _, _} = test_request:put(
+ url() ++ "/db2/_security",
+ ?ADMIN_REQ_HEADERS,
+ jiffy:encode(?SECURITY_OBJECT)
+ ),
% create source docs
- {ok, _, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db/b",
- ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db/c",
- ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db/b",
+ ?ADMIN_REQ_HEADERS,
+ "{\"b\":2,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db/c",
+ ?ADMIN_REQ_HEADERS,
+ "{\"c\":3,\"_access\":[\"y\"]}"
+ ),
% replicate
UserXUrl = string:replace(Url, "http://", "http://x:x@"),
- EJRequestBody = {[
- {<<"source">>, list_to_binary(UserXUrl ++ "/db")},
- {<<"target">>, list_to_binary(UserXUrl ++ "/db2")}
- ]},
- {ok, ResponseCode, _, ResponseBody} = test_request:post(Url ++ "/_replicate",
- ?USERX_REQ_HEADERS, jiffy:encode(EJRequestBody)),
+ EJRequestBody =
+ {[
+ {<<"source">>, list_to_binary(UserXUrl ++ "/db")},
+ {<<"target">>, list_to_binary(UserXUrl ++ "/db2")}
+ ]},
+ {ok, ResponseCode, _, ResponseBody} = test_request:post(
+ Url ++ "/_replicate",
+ ?USERX_REQ_HEADERS,
+ jiffy:encode(EJRequestBody)
+ ),
% ?debugFmt("~nResponseBody: ~p~n", [ResponseBody]),
% assert replication status
@@ -772,28 +1100,34 @@ should_allow_user_to_replicate_from_access_to_access(_PortType, Url) ->
DocsReard = couch_util:get_value(<<"docs_read">>, History),
DocsWritten = couch_util:get_value(<<"docs_written">>, History),
DocWriteFailures = couch_util:get_value(<<"doc_write_failures">>, History),
-
+
?assertEqual(2, MissingChecked),
?assertEqual(2, MissingFound),
?assertEqual(2, DocsReard),
?assertEqual(2, DocsWritten),
?assertEqual(0, DocWriteFailures),
-
+
% assert access in local doc
ReplicationId = couch_util:get_value(<<"replication_id">>, EJResponseBody),
- {ok, 200, _, CheckPoint} = test_request:get(Url ++ "/db/_local/" ++ ReplicationId,
- ?USERX_REQ_HEADERS),
+ {ok, 200, _, CheckPoint} = test_request:get(
+ Url ++ "/db/_local/" ++ ReplicationId,
+ ?USERX_REQ_HEADERS
+ ),
{EJCheckPoint} = jiffy:decode(CheckPoint),
Access = couch_util:get_value(<<"_access">>, EJCheckPoint),
?assertEqual([<<"x">>], Access),
% make sure others can’t read our local docs
- {ok, 403, _, _} = test_request:get(Url ++ "/db/_local/" ++ ReplicationId,
- ?USERY_REQ_HEADERS),
+ {ok, 403, _, _} = test_request:get(
+ Url ++ "/db/_local/" ++ ReplicationId,
+ ?USERY_REQ_HEADERS
+ ),
% assert docs in target db
- {ok, 200, _, ADBody} = test_request:get(Url ++ "/db2/_all_docs?include_docs=true",
- ?ADMIN_REQ_HEADERS),
+ {ok, 200, _, ADBody} = test_request:get(
+ Url ++ "/db2/_all_docs?include_docs=true",
+ ?ADMIN_REQ_HEADERS
+ ),
{Json} = jiffy:decode(ADBody),
?assertEqual(2, proplists:get_value(<<"total_rows">>, Json))
end).
@@ -801,28 +1135,47 @@ should_allow_user_to_replicate_from_access_to_access(_PortType, Url) ->
should_allow_user_to_replicate_from_access_to_no_access(_PortType, Url) ->
?_test(begin
% create source and target dbs
- {ok, 201, _, _} = test_request:put(url() ++ "/db2?q=1&n=1",
- ?ADMIN_REQ_HEADERS, ""),
+ {ok, 201, _, _} = test_request:put(
+ url() ++ "/db2?q=1&n=1",
+ ?ADMIN_REQ_HEADERS,
+ ""
+ ),
% set target db security
- {ok, _, _, _} = test_request:put(url() ++ "/db2/_security",
- ?ADMIN_REQ_HEADERS, jiffy:encode(?SECURITY_OBJECT)),
+ {ok, _, _, _} = test_request:put(
+ url() ++ "/db2/_security",
+ ?ADMIN_REQ_HEADERS,
+ jiffy:encode(?SECURITY_OBJECT)
+ ),
% create source docs
- {ok, _, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db/b",
- ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db/c",
- ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db/b",
+ ?ADMIN_REQ_HEADERS,
+ "{\"b\":2,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db/c",
+ ?ADMIN_REQ_HEADERS,
+ "{\"c\":3,\"_access\":[\"y\"]}"
+ ),
% replicate
UserXUrl = string:replace(Url, "http://", "http://x:x@"),
- EJRequestBody = {[
- {<<"source">>, list_to_binary(UserXUrl ++ "/db")},
- {<<"target">>, list_to_binary(UserXUrl ++ "/db2")}
- ]},
- {ok, ResponseCode, _, ResponseBody} = test_request:post(Url ++ "/_replicate",
- ?USERX_REQ_HEADERS, jiffy:encode(EJRequestBody)),
+ EJRequestBody =
+ {[
+ {<<"source">>, list_to_binary(UserXUrl ++ "/db")},
+ {<<"target">>, list_to_binary(UserXUrl ++ "/db2")}
+ ]},
+ {ok, ResponseCode, _, ResponseBody} = test_request:post(
+ Url ++ "/_replicate",
+ ?USERX_REQ_HEADERS,
+ jiffy:encode(EJRequestBody)
+ ),
% assert replication status
{EJResponseBody} = jiffy:decode(ResponseBody),
@@ -835,16 +1188,18 @@ should_allow_user_to_replicate_from_access_to_no_access(_PortType, Url) ->
DocsReard = couch_util:get_value(<<"docs_read">>, History),
DocsWritten = couch_util:get_value(<<"docs_written">>, History),
DocWriteFailures = couch_util:get_value(<<"doc_write_failures">>, History),
-
+
?assertEqual(2, MissingChecked),
?assertEqual(2, MissingFound),
?assertEqual(2, DocsReard),
?assertEqual(2, DocsWritten),
?assertEqual(0, DocWriteFailures),
-
+
% assert docs in target db
- {ok, 200, _, ADBody} = test_request:get(Url ++ "/db2/_all_docs?include_docs=true",
- ?ADMIN_REQ_HEADERS),
+ {ok, 200, _, ADBody} = test_request:get(
+ Url ++ "/db2/_all_docs?include_docs=true",
+ ?ADMIN_REQ_HEADERS
+ ),
{Json} = jiffy:decode(ADBody),
?assertEqual(2, proplists:get_value(<<"total_rows">>, Json))
end).
@@ -852,11 +1207,17 @@ should_allow_user_to_replicate_from_access_to_no_access(_PortType, Url) ->
should_allow_user_to_replicate_from_no_access_to_access(_PortType, Url) ->
?_test(begin
% create source and target dbs
- {ok, 201, _, _} = test_request:put(url() ++ "/db2?q=1&n=1",
- ?ADMIN_REQ_HEADERS, ""),
+ {ok, 201, _, _} = test_request:put(
+ url() ++ "/db2?q=1&n=1",
+ ?ADMIN_REQ_HEADERS,
+ ""
+ ),
% set target db security
- {ok, _, _, _} = test_request:put(url() ++ "/db2/_security",
- ?ADMIN_REQ_HEADERS, jiffy:encode(?SECURITY_OBJECT)),
+ {ok, _, _, _} = test_request:put(
+ url() ++ "/db2/_security",
+ ?ADMIN_REQ_HEADERS,
+ jiffy:encode(?SECURITY_OBJECT)
+ ),
% leave for easier debugging
% VduFun = <<"function(newdoc, olddoc, userctx) {if(newdoc._id == \"b\") throw({'forbidden':'fail'})}">>,
@@ -867,22 +1228,34 @@ should_allow_user_to_replicate_from_no_access_to_access(_PortType, Url) ->
% {ok, _, _, _} = test_request:put(Url ++ "/db/_design/vdu",
% ?ADMIN_REQ_HEADERS, jiffy:encode(DDoc)),
% create source docs
- {ok, _, _, _} = test_request:put(Url ++ "/db2/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db2/b",
- ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db2/c",
- ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
-
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db2/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db2/b",
+ ?ADMIN_REQ_HEADERS,
+ "{\"b\":2,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db2/c",
+ ?ADMIN_REQ_HEADERS,
+ "{\"c\":3,\"_access\":[\"y\"]}"
+ ),
% replicate
UserXUrl = string:replace(Url, "http://", "http://x:x@"),
- EJRequestBody = {[
- {<<"source">>, list_to_binary(UserXUrl ++ "/db2")},
- {<<"target">>, list_to_binary(UserXUrl ++ "/db")}
- ]},
- {ok, ResponseCode, _, ResponseBody} = test_request:post(Url ++ "/_replicate",
- ?USERX_REQ_HEADERS, jiffy:encode(EJRequestBody)),
+ EJRequestBody =
+ {[
+ {<<"source">>, list_to_binary(UserXUrl ++ "/db2")},
+ {<<"target">>, list_to_binary(UserXUrl ++ "/db")}
+ ]},
+ {ok, ResponseCode, _, ResponseBody} = test_request:post(
+ Url ++ "/_replicate",
+ ?USERX_REQ_HEADERS,
+ jiffy:encode(EJRequestBody)
+ ),
% assert replication status
{EJResponseBody} = jiffy:decode(ResponseBody),
@@ -895,16 +1268,18 @@ should_allow_user_to_replicate_from_no_access_to_access(_PortType, Url) ->
DocsReard = couch_util:get_value(<<"docs_read">>, History),
DocsWritten = couch_util:get_value(<<"docs_written">>, History),
DocWriteFailures = couch_util:get_value(<<"doc_write_failures">>, History),
-
+
?assertEqual(3, MissingChecked),
?assertEqual(3, MissingFound),
?assertEqual(3, DocsReard),
?assertEqual(2, DocsWritten),
?assertEqual(1, DocWriteFailures),
-
+
% assert docs in target db
- {ok, 200, _, ADBody} = test_request:get(Url ++ "/db/_all_docs?include_docs=true",
- ?ADMIN_REQ_HEADERS),
+ {ok, 200, _, ADBody} = test_request:get(
+ Url ++ "/db/_all_docs?include_docs=true",
+ ?ADMIN_REQ_HEADERS
+ ),
{Json} = jiffy:decode(ADBody),
?assertEqual(2, proplists:get_value(<<"total_rows">>, Json))
end).
@@ -912,33 +1287,58 @@ should_allow_user_to_replicate_from_no_access_to_access(_PortType, Url) ->
should_allow_user_to_replicate_from_no_access_to_no_access(_PortType, Url) ->
?_test(begin
% create source and target dbs
- {ok, 201, _, _} = test_request:put(url() ++ "/db2?q=1&n=1",
- ?ADMIN_REQ_HEADERS, ""),
+ {ok, 201, _, _} = test_request:put(
+ url() ++ "/db2?q=1&n=1",
+ ?ADMIN_REQ_HEADERS,
+ ""
+ ),
% set target db security
- {ok, _, _, _} = test_request:put(url() ++ "/db2/_security",
- ?ADMIN_REQ_HEADERS, jiffy:encode(?SECURITY_OBJECT)),
-
- {ok, 201, _, _} = test_request:put(url() ++ "/db3?q=1&n=1",
- ?ADMIN_REQ_HEADERS, ""),
+ {ok, _, _, _} = test_request:put(
+ url() ++ "/db2/_security",
+ ?ADMIN_REQ_HEADERS,
+ jiffy:encode(?SECURITY_OBJECT)
+ ),
+
+ {ok, 201, _, _} = test_request:put(
+ url() ++ "/db3?q=1&n=1",
+ ?ADMIN_REQ_HEADERS,
+ ""
+ ),
% set target db security
- {ok, _, _, _} = test_request:put(url() ++ "/db3/_security",
- ?ADMIN_REQ_HEADERS, jiffy:encode(?SECURITY_OBJECT)),
+ {ok, _, _, _} = test_request:put(
+ url() ++ "/db3/_security",
+ ?ADMIN_REQ_HEADERS,
+ jiffy:encode(?SECURITY_OBJECT)
+ ),
% create source docs
- {ok, _, _, _} = test_request:put(Url ++ "/db2/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db2/b",
- ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db2/c",
- ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db2/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db2/b",
+ ?ADMIN_REQ_HEADERS,
+ "{\"b\":2,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db2/c",
+ ?ADMIN_REQ_HEADERS,
+ "{\"c\":3,\"_access\":[\"y\"]}"
+ ),
% replicate
UserXUrl = string:replace(Url, "http://", "http://x:x@"),
- EJRequestBody = {[
- {<<"source">>, list_to_binary(UserXUrl ++ "/db2")},
- {<<"target">>, list_to_binary(UserXUrl ++ "/db3")}
- ]},
- {ok, ResponseCode, _, ResponseBody} = test_request:post(Url ++ "/_replicate",
- ?USERX_REQ_HEADERS, jiffy:encode(EJRequestBody)),
+ EJRequestBody =
+ {[
+ {<<"source">>, list_to_binary(UserXUrl ++ "/db2")},
+ {<<"target">>, list_to_binary(UserXUrl ++ "/db3")}
+ ]},
+ {ok, ResponseCode, _, ResponseBody} = test_request:post(
+ Url ++ "/_replicate",
+ ?USERX_REQ_HEADERS,
+ jiffy:encode(EJRequestBody)
+ ),
% assert replication status
{EJResponseBody} = jiffy:decode(ResponseBody),
@@ -951,72 +1351,97 @@ should_allow_user_to_replicate_from_no_access_to_no_access(_PortType, Url) ->
DocsReard = couch_util:get_value(<<"docs_read">>, History),
DocsWritten = couch_util:get_value(<<"docs_written">>, History),
DocWriteFailures = couch_util:get_value(<<"doc_write_failures">>, History),
-
+
?assertEqual(3, MissingChecked),
?assertEqual(3, MissingFound),
?assertEqual(3, DocsReard),
?assertEqual(3, DocsWritten),
?assertEqual(0, DocWriteFailures),
-
+
% assert docs in target db
- {ok, 200, _, ADBody} = test_request:get(Url ++ "/db3/_all_docs?include_docs=true",
- ?ADMIN_REQ_HEADERS),
+ {ok, 200, _, ADBody} = test_request:get(
+ Url ++ "/db3/_all_docs?include_docs=true",
+ ?ADMIN_REQ_HEADERS
+ ),
{Json} = jiffy:decode(ADBody),
?assertEqual(3, proplists:get_value(<<"total_rows">>, Json))
end).
% revs_diff
should_not_allow_user_to_revs_diff_other_docs(_PortType, Url) ->
- ?_test(begin
- % create test docs
- {ok, _, _, _} = test_request:put(Url ++ "/db/a",
- ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:put(Url ++ "/db/b",
- ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, _, _, V} = test_request:put(Url ++ "/db/c",
- ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
-
- % nothing missing
- RevsDiff = {[
- {<<"a">>, [
- <<"1-23202479633c2b380f79507a776743d5">>
- ]}
- ]},
- {ok, GoodCode, _, GoodBody} = test_request:post(Url ++ "/db/_revs_diff",
- ?USERX_REQ_HEADERS, jiffy:encode(RevsDiff)),
- EJGoodBody = jiffy:decode(GoodBody),
- ?assertEqual(200, GoodCode),
- ?assertEqual({[]}, EJGoodBody),
-
- % something missing
- MissingRevsDiff = {[
- {<<"a">>, [
- <<"1-missing">>
- ]}
- ]},
- {ok, MissingCode, _, MissingBody} = test_request:post(Url ++ "/db/_revs_diff",
- ?USERX_REQ_HEADERS, jiffy:encode(MissingRevsDiff)),
- EJMissingBody = jiffy:decode(MissingBody),
- ?assertEqual(200, MissingCode),
- MissingExpect = {[
- {<<"a">>, {[
- {<<"missing">>, [<<"1-missing">>]}
- ]}}
- ]},
- ?assertEqual(MissingExpect, EJMissingBody),
-
- % other doc
- OtherRevsDiff = {[
- {<<"c">>, [
- <<"1-92aef5b0e4a3f4db0aba1320869bc95d">>
- ]}
- ]},
- {ok, OtherCode, _, OtherBody} = test_request:post(Url ++ "/db/_revs_diff",
- ?USERX_REQ_HEADERS, jiffy:encode(OtherRevsDiff)),
- EJOtherBody = jiffy:decode(OtherBody),
- ?assertEqual(200, OtherCode),
- ?assertEqual({[]}, EJOtherBody)
- end).
+ ?_test(begin
+ % create test docs
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS,
+ "{\"a\":1,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, _} = test_request:put(
+ Url ++ "/db/b",
+ ?ADMIN_REQ_HEADERS,
+ "{\"b\":2,\"_access\":[\"x\"]}"
+ ),
+ {ok, _, _, V} = test_request:put(
+ Url ++ "/db/c",
+ ?ADMIN_REQ_HEADERS,
+ "{\"c\":3,\"_access\":[\"y\"]}"
+ ),
+
+ % nothing missing
+ RevsDiff =
+ {[
+ {<<"a">>, [
+ <<"1-23202479633c2b380f79507a776743d5">>
+ ]}
+ ]},
+ {ok, GoodCode, _, GoodBody} = test_request:post(
+ Url ++ "/db/_revs_diff",
+ ?USERX_REQ_HEADERS,
+ jiffy:encode(RevsDiff)
+ ),
+ EJGoodBody = jiffy:decode(GoodBody),
+ ?assertEqual(200, GoodCode),
+ ?assertEqual({[]}, EJGoodBody),
+
+ % something missing
+ MissingRevsDiff =
+ {[
+ {<<"a">>, [
+ <<"1-missing">>
+ ]}
+ ]},
+ {ok, MissingCode, _, MissingBody} = test_request:post(
+ Url ++ "/db/_revs_diff",
+ ?USERX_REQ_HEADERS,
+ jiffy:encode(MissingRevsDiff)
+ ),
+ EJMissingBody = jiffy:decode(MissingBody),
+ ?assertEqual(200, MissingCode),
+ MissingExpect =
+ {[
+ {<<"a">>,
+ {[
+ {<<"missing">>, [<<"1-missing">>]}
+ ]}}
+ ]},
+ ?assertEqual(MissingExpect, EJMissingBody),
+
+ % other doc
+ OtherRevsDiff =
+ {[
+ {<<"c">>, [
+ <<"1-92aef5b0e4a3f4db0aba1320869bc95d">>
+ ]}
+ ]},
+ {ok, OtherCode, _, OtherBody} = test_request:post(
+ Url ++ "/db/_revs_diff",
+ ?USERX_REQ_HEADERS,
+ jiffy:encode(OtherRevsDiff)
+ ),
+ EJOtherBody = jiffy:decode(OtherBody),
+ ?assertEqual(200, OtherCode),
+ ?assertEqual({[]}, EJOtherBody)
+ end).
%% ------------------------------------------------------------------
%% Internal Function Definitions
%% ------------------------------------------------------------------
diff --git a/src/couch/test/eunit/couchdb_update_conflicts_tests.erl b/src/couch/test/eunit/couchdb_update_conflicts_tests.erl
index 953ddd703..d75b335b1 100644
--- a/src/couch/test/eunit/couchdb_update_conflicts_tests.erl
+++ b/src/couch/test/eunit/couchdb_update_conflicts_tests.erl
@@ -18,7 +18,8 @@
-define(i2l(I), integer_to_list(I)).
-define(DOC_ID, <<"foobar">>).
-define(LOCAL_DOC_ID, <<"_local/foobar">>).
--define(NUM_CLIENTS, [100, 500 ]). % TODO: enable 1000, 2000, 5000, 10000]).
+% TODO: enable 1000, 2000, 5000, 10000]).
+-define(NUM_CLIENTS, [100, 500]).
-define(TIMEOUT, 200000).
start() ->
diff --git a/src/couch_index/src/couch_index_updater.erl b/src/couch_index/src/couch_index_updater.erl
index 66d760622..ab84b0955 100644
--- a/src/couch_index/src/couch_index_updater.erl
+++ b/src/couch_index/src/couch_index_updater.erl
@@ -124,7 +124,7 @@ update(Idx, Mod, IdxState) ->
DocOpts =
case lists:member(local_seq, UpdateOpts) of
true -> [conflicts, deleted_conflicts, local_seq, deleted];
- _ -> [conflicts, deleted_conflicts,local_seq, deleted]
+ _ -> [conflicts, deleted_conflicts, local_seq, deleted]
end,
couch_util:with_db(DbName, fun(Db) ->
@@ -142,9 +142,9 @@ update(Idx, Mod, IdxState) ->
end,
GetInfo = fun
- (#full_doc_info{id=Id, update_seq=Seq, deleted=Del,access=Access}=FDI) ->
+ (#full_doc_info{id = Id, update_seq = Seq, deleted = Del, access = Access} = FDI) ->
{Id, Seq, Del, couch_doc:to_doc_info(FDI), Access};
- (#doc_info{id=Id, high_seq=Seq, revs=[RI|_],access=Access}=DI) ->
+ (#doc_info{id = Id, high_seq = Seq, revs = [RI | _], access = Access} = DI) ->
{Id, Seq, RI#rev_info.deleted, DI, Access}
end,
@@ -155,19 +155,20 @@ update(Idx, Mod, IdxState) ->
{false, <<"_design/", _/binary>>} ->
{nil, Seq};
_ ->
- case IndexName of % TODO: move into outer case statement
+ % TODO: move into outer case statement
+ case IndexName of
<<"_design/_access">> ->
{ok, Doc} = couch_db:open_doc_int(Db, DocInfo, DocOpts),
% TODO: hande conflicted docs in _access index
% probably remove
- [RevInfo|_] = DocInfo#doc_info.revs,
+ [RevInfo | _] = DocInfo#doc_info.revs,
Doc1 = Doc#doc{
meta = [{body_sp, RevInfo#rev_info.body_sp}],
access = Access
},
{Doc1, Seq};
_ when Deleted ->
- {#doc{id=DocId, deleted=true}, Seq};
+ {#doc{id = DocId, deleted = true}, Seq};
_ ->
{ok, Doc} = couch_db:open_doc_int(Db, DocInfo, DocOpts),
{Doc, Seq}
diff --git a/src/couch_index/src/couch_index_util.erl b/src/couch_index/src/couch_index_util.erl
index 47133db0f..beb0f5569 100644
--- a/src/couch_index/src/couch_index_util.erl
+++ b/src/couch_index/src/couch_index_util.erl
@@ -31,7 +31,7 @@ index_file(Module, DbName, FileName) ->
load_doc(Db, #doc_info{} = DI, Opts) ->
Deleted = lists:member(deleted, Opts),
- % MyDoc = ,
+ % MyDoc = ,
%{ok, MyDoc2} = MyDoc,
%couch_log:error("~ncouch_index_util:load_doc(): Doc: ~p, Deleted ~p~n", [MyDoc2, MyDoc2#doc.deleted]),
case catch (couch_db:open_doc(Db, DI, Opts)) of
diff --git a/src/couch_mrview/src/couch_mrview.erl b/src/couch_mrview/src/couch_mrview.erl
index 79b2b8bec..2cb74fac4 100644
--- a/src/couch_mrview/src/couch_mrview.erl
+++ b/src/couch_mrview/src/couch_mrview.erl
@@ -266,22 +266,27 @@ query_all_docs(Db, Args0, Callback, Acc) ->
access_ddoc() ->
#doc{
id = <<"_design/_access">>,
- body = {[
- {<<"language">>,<<"_access">>},
- {<<"options">>, {[
- {<<"include_design">>, true}
- ]}},
- {<<"views">>, {[
- {<<"_access_by_id">>, {[
- {<<"map">>, <<"_access/by-id-map">>},
- {<<"reduce">>, <<"_count">>}
- ]}},
- {<<"_access_by_seq">>, {[
- {<<"map">>, <<"_access/by-seq-map">>},
- {<<"reduce">>, <<"_count">>}
- ]}}
- ]}}
- ]}
+ body =
+ {[
+ {<<"language">>, <<"_access">>},
+ {<<"options">>,
+ {[
+ {<<"include_design">>, true}
+ ]}},
+ {<<"views">>,
+ {[
+ {<<"_access_by_id">>,
+ {[
+ {<<"map">>, <<"_access/by-id-map">>},
+ {<<"reduce">>, <<"_count">>}
+ ]}},
+ {<<"_access_by_seq">>,
+ {[
+ {<<"map">>, <<"_access/by-seq-map">>},
+ {<<"reduce">>, <<"_count">>}
+ ]}}
+ ]}}
+ ]}
}.
query_changes_access(Db, StartSeq, Fun, Options, Acc) ->
DDoc = access_ddoc(),
@@ -289,15 +294,16 @@ query_changes_access(Db, StartSeq, Fun, Options, Acc) ->
UserName = UserCtx#user_ctx.name,
%% % TODO: add roles
Args1 = prefix_startkey_endkey(UserName, #mrargs{}, fwd),
- Args2 = Args1#mrargs{deleted=true},
- Args = Args2#mrargs{reduce=false},
+ Args2 = Args1#mrargs{deleted = true},
+ Args = Args2#mrargs{reduce = false},
%% % filter out the user-prefix from the key, so _all_docs looks normal
%% % this isn’t a separate function because I’m binding Callback0 and I don’t
%% % know the Erlang equivalent of JS’s fun.bind(this, newarg)
Callback = fun
- ({meta, _}, Acc0) ->
- {ok, Acc0}; % ignore for now
- ({row, Props}, Acc0) ->
+ ({meta, _}, Acc0) ->
+ % ignore for now
+ {ok, Acc0};
+ ({row, Props}, Acc0) ->
% turn row into FDI
Value = couch_util:get_value(value, Props),
[Owner, Seq] = couch_util:get_value(key, Props),
@@ -307,7 +313,16 @@ query_changes_access(Db, StartSeq, Fun, Options, Acc) ->
[Pos, RevId] = string:split(?b2l(Rev), "-"),
FDI = #full_doc_info{
id = proplists:get_value(id, Props),
- rev_tree = [{list_to_integer(Pos), {?l2b(RevId), #leaf{deleted=Deleted, ptr=BodySp, seq=Seq, sizes=#size_info{}}, []}}],
+ rev_tree = [
+ {
+ list_to_integer(Pos),
+ {
+ ?l2b(RevId),
+ #leaf{deleted = Deleted, ptr = BodySp, seq = Seq, sizes = #size_info{}},
+ []
+ }
+ }
+ ],
deleted = Deleted,
update_seq = 0,
sizes = #size_info{},
@@ -315,8 +330,9 @@ query_changes_access(Db, StartSeq, Fun, Options, Acc) ->
},
Fun(FDI, Acc0);
(_Else, Acc0) ->
- {ok, Acc0} % ignore for now
- end,
+ % ignore for now
+ {ok, Acc0}
+ end,
VName = <<"_access_by_seq">>,
query_view(Db, DDoc, VName, Args, Callback, Acc).
@@ -327,7 +343,7 @@ query_all_docs_access(Db, Args0, Callback0, Acc) ->
UserCtx = couch_db:get_user_ctx(Db),
UserName = UserCtx#user_ctx.name,
Args1 = prefix_startkey_endkey(UserName, Args0, Args0#mrargs.direction),
- Args = Args1#mrargs{reduce=false, extra=Args1#mrargs.extra ++ [{all_docs_access, true}]},
+ Args = Args1#mrargs{reduce = false, extra = Args1#mrargs.extra ++ [{all_docs_access, true}]},
Callback = fun
({row, Props}, Acc0) ->
% filter out the user-prefix from the key, so _all_docs looks normal
@@ -339,34 +355,37 @@ query_all_docs_access(Db, Args0, Callback0, Acc) ->
Callback0({row, Row}, Acc0);
(Row, Acc0) ->
Callback0(Row, Acc0)
- end,
+ end,
VName = <<"_access_by_id">>,
query_view(Db, DDoc, VName, Args, Callback, Acc).
prefix_startkey_endkey(UserName, Args, fwd) ->
- #mrargs{start_key=StartKey, end_key=EndKey} = Args,
- Args#mrargs {
- start_key = case StartKey of
- undefined -> [UserName];
- StartKey -> [UserName, StartKey]
- end,
- end_key = case EndKey of
- undefined -> [UserName, {}];
- EndKey -> [UserName, EndKey, {}]
- end
+ #mrargs{start_key = StartKey, end_key = EndKey} = Args,
+ Args#mrargs{
+ start_key =
+ case StartKey of
+ undefined -> [UserName];
+ StartKey -> [UserName, StartKey]
+ end,
+ end_key =
+ case EndKey of
+ undefined -> [UserName, {}];
+ EndKey -> [UserName, EndKey, {}]
+ end
};
-
prefix_startkey_endkey(UserName, Args, rev) ->
- #mrargs{start_key=StartKey, end_key=EndKey} = Args,
- Args#mrargs {
- end_key = case StartKey of
- undefined -> [UserName];
- StartKey -> [UserName, StartKey]
- end,
- start_key = case EndKey of
- undefined -> [UserName, {}];
- EndKey -> [UserName, EndKey, {}]
- end
+ #mrargs{start_key = StartKey, end_key = EndKey} = Args,
+ Args#mrargs{
+ end_key =
+ case StartKey of
+ undefined -> [UserName];
+ StartKey -> [UserName, StartKey]
+ end,
+ start_key =
+ case EndKey of
+ undefined -> [UserName, {}];
+ EndKey -> [UserName, EndKey, {}]
+ end
}.
query_all_docs_admin(Db, Args0, Callback, Acc) ->
Sig = couch_util:with_db(Db, fun(WDb) ->
diff --git a/src/couch_mrview/src/couch_mrview_updater.erl b/src/couch_mrview/src/couch_mrview_updater.erl
index 5d58ab05d..83d21c036 100644
--- a/src/couch_mrview/src/couch_mrview_updater.erl
+++ b/src/couch_mrview/src/couch_mrview_updater.erl
@@ -176,36 +176,38 @@ map_docs(Parent, #mrst{db_name = DbName, idx_name = IdxName} = State0) ->
DocFun = fun
({nil, Seq, _}, {SeqAcc, Results}) ->
{erlang:max(Seq, SeqAcc), Results};
- ({Id, Seq, Rev, #doc{deleted=true, body=Body, meta=Meta}}, {SeqAcc, Results}) ->
- % _access needs deleted docs
- case IdxName of
- <<"_design/_access">> ->
- % splice in seq
- {Start, Rev1} = Rev,
- Doc = #doc{
- id = Id,
- revs = {Start, [Rev1]},
- body = {make_deleted_body(Body, Meta, Seq)}, %% todo: only keep _access and add _seq
- deleted = true
- },
- {ok, Res} = couch_query_servers:map_doc_raw(QServer, Doc),
- {erlang:max(Seq, SeqAcc), [{Id, Seq, Rev, Res} | Results]};
- _Else ->
- {erlang:max(Seq, SeqAcc), [{Id, Seq, Rev, []} | Results]}
- end;
- ({Id, Seq, Doc}, {SeqAcc, Results}) ->
- couch_stats:increment_counter([couchdb, mrview, map_doc]),
- % IdxName: ~p, Doc: ~p~n~n", [IdxName, Doc]),
- Doc0 = case IdxName of
+ ({Id, Seq, Rev, #doc{deleted = true, body = Body, meta = Meta}}, {SeqAcc, Results}) ->
+ % _access needs deleted docs
+ case IdxName of
<<"_design/_access">> ->
% splice in seq
- {Props} = Doc#doc.body,
- BodySp = couch_util:get_value(body_sp, Doc#doc.meta),
- Doc#doc{
- body = {Props++[{<<"_seq">>, Seq}, {<<"_body_sp">>, BodySp}]}
- };
+ {Start, Rev1} = Rev,
+ Doc = #doc{
+ id = Id,
+ revs = {Start, [Rev1]},
+ %% todo: only keep _access and add _seq
+ body = {make_deleted_body(Body, Meta, Seq)},
+ deleted = true
+ },
+ {ok, Res} = couch_query_servers:map_doc_raw(QServer, Doc),
+ {erlang:max(Seq, SeqAcc), [{Id, Seq, Rev, Res} | Results]};
_Else ->
- Doc
+ {erlang:max(Seq, SeqAcc), [{Id, Seq, Rev, []} | Results]}
+ end;
+ ({Id, Seq, Doc}, {SeqAcc, Results}) ->
+ couch_stats:increment_counter([couchdb, mrview, map_doc]),
+ % IdxName: ~p, Doc: ~p~n~n", [IdxName, Doc]),
+ Doc0 =
+ case IdxName of
+ <<"_design/_access">> ->
+ % splice in seq
+ {Props} = Doc#doc.body,
+ BodySp = couch_util:get_value(body_sp, Doc#doc.meta),
+ Doc#doc{
+ body = {Props ++ [{<<"_seq">>, Seq}, {<<"_body_sp">>, BodySp}]}
+ };
+ _Else ->
+ Doc
end,
{ok, Res} = couch_query_servers:map_doc_raw(QServer, Doc0),
{erlang:max(Seq, SeqAcc), [{Id, Res} | Results]}
diff --git a/src/couch_mrview/src/couch_mrview_util.erl b/src/couch_mrview/src/couch_mrview_util.erl
index 7991487ff..4bc11997c 100644
--- a/src/couch_mrview/src/couch_mrview_util.erl
+++ b/src/couch_mrview/src/couch_mrview_util.erl
@@ -438,7 +438,7 @@ reduce_to_count(Reductions) ->
FinalReduction = couch_btree:final_reduce(CountReduceFun, Reductions),
get_count(FinalReduction).
-get_access_row_count(#mrview{btree=Bt}, UserName) ->
+get_access_row_count(#mrview{btree = Bt}, UserName) ->
couch_btree:full_reduce_with_options(Bt, [
{start_key, UserName}
]).
diff --git a/src/couch_replicator/src/couch_replicator.erl b/src/couch_replicator/src/couch_replicator.erl
index ac3807d11..e1dd627c7 100644
--- a/src/couch_replicator/src/couch_replicator.erl
+++ b/src/couch_replicator/src/couch_replicator.erl
@@ -77,13 +77,16 @@ replicate(PostBody, Ctx) ->
false ->
check_authorization(RepId, UserCtx),
{ok, Listener} = rep_result_listener(RepId),
- Result = case do_replication_loop(Rep) of % TODO: review why we need this
- {ok, {ResultJson}} ->
- {PublicRepId, _} = couch_replicator_ids:replication_id(Rep), % TODO: check with options
- {ok, {[{<<"replication_id">>, ?l2b(PublicRepId)} | ResultJson]}};
- Else ->
- Else
- end,
+ % TODO: review why we need this
+ Result =
+ case do_replication_loop(Rep) of
+ {ok, {ResultJson}} ->
+ % TODO: check with options
+ {PublicRepId, _} = couch_replicator_ids:replication_id(Rep),
+ {ok, {[{<<"replication_id">>, ?l2b(PublicRepId)} | ResultJson]}};
+ Else ->
+ Else
+ end,
couch_replicator_notifier:stop(Listener),
Result
end.
diff --git a/src/couch_replicator/src/couch_replicator_scheduler_job.erl b/src/couch_replicator/src/couch_replicator_scheduler_job.erl
index ac979d37c..bc4708b22 100644
--- a/src/couch_replicator/src/couch_replicator_scheduler_job.erl
+++ b/src/couch_replicator/src/couch_replicator_scheduler_job.erl
@@ -859,9 +859,11 @@ do_checkpoint(State) ->
try
{SrcRevPos, SrcRevId} = update_checkpoint(
- Source, SourceLog#doc{body = NewRepHistory}, SrcAccess, UserCtx, source),
+ Source, SourceLog#doc{body = NewRepHistory}, SrcAccess, UserCtx, source
+ ),
{TgtRevPos, TgtRevId} = update_checkpoint(
- Target, TargetLog#doc{body = NewRepHistory}, TgtAccess, UserCtx, target),
+ Target, TargetLog#doc{body = NewRepHistory}, TgtAccess, UserCtx, target
+ ),
NewState = State#rep_state{
checkpoint_history = NewRepHistory,
committed_seq = NewTsSeq,
@@ -907,10 +909,11 @@ update_checkpoint(Db, Doc, Access, UserCtx, DbType) ->
update_checkpoint(Db, #doc{id = LogId} = Doc0, Access, UserCtx) ->
% if db has _access, then:
% get userCtx from replication and splice into doc _access
- Doc = case Access of
- true -> Doc0#doc{access = [UserCtx#user_ctx.name]};
- _False -> Doc0
- end,
+ Doc =
+ case Access of
+ true -> Doc0#doc{access = [UserCtx#user_ctx.name]};
+ _False -> Doc0
+ end,
try
case couch_replicator_api_wrap:update_doc(Db, Doc, [delay_commit]) of
diff --git a/src/fabric/src/fabric_doc_update.erl b/src/fabric/src/fabric_doc_update.erl
index e38887659..f782fe3dd 100644
--- a/src/fabric/src/fabric_doc_update.erl
+++ b/src/fabric/src/fabric_doc_update.erl
@@ -423,7 +423,7 @@ doc_update1() ->
?assertEqual(
% TODO: find out why we had to swap this
- {error, [{Doc2,{error,internal_server_error}},{Doc1,{accepted,"A"}}]},
+ {error, [{Doc2, {error, internal_server_error}}, {Doc1, {accepted, "A"}}]},
ReplyW5
).
@@ -454,7 +454,7 @@ doc_update2() ->
handle_message({rexi_EXIT, 1}, lists:nth(3, Shards), Acc2),
?assertEqual(
- {accepted, [{Doc2,{accepted,Doc2}}, {Doc1,{accepted,Doc1}}]},
+ {accepted, [{Doc2, {accepted, Doc2}}, {Doc1, {accepted, Doc1}}]},
Reply
).
@@ -483,7 +483,7 @@ doc_update3() ->
{stop, Reply} =
handle_message({ok, [{ok, Doc1}, {ok, Doc2}]}, lists:nth(3, Shards), Acc2),
- ?assertEqual({ok, [{Doc2, {ok,Doc2}},{Doc1, {ok, Doc1}}]},Reply).
+ ?assertEqual({ok, [{Doc2, {ok, Doc2}}, {Doc1, {ok, Doc1}}]}, Reply).
handle_all_dbs_active() ->
Doc1 = #doc{revs = {1, [<<"foo">>]}},