Skip to content

Commit 23ac46e

Browse files
committed
Improve the QuickJS update function scanning
* Noticed some design documents crashing because they are missing some of the expected `req` fields. When an early `TypeError("req.form is undefined")` error is thrown, it shortcuts the evaluation and we're missing covering that ddoc. To fix it, fill out [1] more of the mock request object so we get better coverage in the scanner. * Handle error raised from the update function similar to how we handle other such errors in other function. From update functions they look like `render_error`. [1] https://docs.couchdb.org/en/stable/json-structure.html#request-object
1 parent 1c00539 commit 23ac46e

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

src/couch_quickjs/src/couch_quickjs_scanner_plugin.erl

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,31 @@
6464
%
6565
-define(INTEDERMINISM_HEURISTICS, [<<"Math.random()">>, <<"Date.now()">>, <<"new Date()">>]).
6666

67+
% Mock JS request object. Used by filter and update handlers
68+
% See https://docs.couchdb.org/en/stable/json-structure.html#request-object
69+
-define(MOCK_REQ, #{
70+
<<"info">> => #{
71+
<<"committed_update_seq">> => 42,
72+
<<"db_name">> => <<"foo">>,
73+
<<"doc_count">> => 42,
74+
<<"doc_del_count">> => 42,
75+
<<"sizes">> => #{<<"active">> => 42, <<"disk">> => 42, <<"external">> => 42}
76+
},
77+
<<"query">> => #{},
78+
<<"body">> => #{},
79+
<<"method">> => <<"POST">>,
80+
<<"headers">> => #{},
81+
<<"form">> => #{},
82+
<<"cookie">> => #{},
83+
<<"userCtx">> => #{},
84+
<<"secObj">> => #{},
85+
<<"path">> => [<<"a">>, <<"b">>, <<"c">>],
86+
<<"requested_path">> => [<<"a">>, <<"b">>, <<"c">>],
87+
<<"raw_path">> => <<"a/b/c">>,
88+
<<"peer">> => <<"127.0.0.1">>,
89+
<<"uuid">> => <<"2f3aaf5c54d94f982f384c6f8000197b">>
90+
}).
91+
6792
% Behavior callbacks
6893

6994
start(SId, #{}) ->
@@ -716,6 +741,8 @@ expected_error({error, {_, {<<"SyntaxError">>, _}}}, {error, {_, {<<"SyntaxError
716741
true;
717742
expected_error({error, {_, {<<"ReferenceError">>, _}}}, {error, {_, {<<"ReferenceError">>, _}}}) ->
718743
true;
744+
expected_error({error, {_, {<<"render_error">>, _}}}, {error, {_, {<<"render_error">>, _}}}) ->
745+
true;
719746
expected_error(_, _) ->
720747
false.
721748

@@ -767,13 +794,12 @@ nouveau_index_doc(#proc{} = Proc, {[_ | _]} = Doc) ->
767794

768795
filter_doc(#proc{} = Proc, DDocId, FName, {[_ | _]} = Doc) ->
769796
% Add a mock request object so param access doesn't throw a TypeError
770-
MockReq = #{<<"query">> => #{}},
771-
prompt(Proc, [<<"ddoc">>, DDocId, [<<"filters">>, FName], [[Doc], MockReq]]).
797+
prompt(Proc, [<<"ddoc">>, DDocId, [<<"filters">>, FName], [[Doc], ?MOCK_REQ]]).
772798

773799
update_doc(#proc{} = Proc, DDocId, UName, {[_ | _] = Props} = Doc) ->
774800
% Use a mock object. It's better than nothing at least. We don't know
775801
% what the user might post.
776-
MockReq = #{<<"body">> => #{}, <<"method">> => <<"POST">>, <<"headers">> => #{}},
802+
MockReq = ?MOCK_REQ,
777803
MockReq1 =
778804
case couch_util:get_value(<<"_id">>, Props) of
779805
Id when is_binary(Id) -> MockReq#{<<"id">> => Id};

src/couch_quickjs/test/couch_quickjs_scanner_plugin_tests.erl

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,17 @@ ddoc_update(Doc) ->
651651
" return [null, 'got_dollar_one'];\n"
652652
" }\n"
653653
"}"
654-
>>
654+
>>,
655+
u2 => <<
656+
"function(doc, req) {\n"
657+
" if (typeof(req.form) === 'object') {\n"
658+
" return [null, 'has_form']; \n"
659+
" } else { \n"
660+
" return [null, 'no_form'];\n"
661+
" }\n"
662+
"}"
663+
>>,
664+
u3 => <<"function(doc, req) {throw('Potato')}">>
655665
}
656666
}.
657667

0 commit comments

Comments
 (0)