details: https://hg.nginx.org/njs/rev/08a912ab9520 branches: changeset: 2129:08a912ab9520 user: Dmitry Volyntsev <xei...@nginx.com> date: Mon May 22 17:59:47 2023 -0700 description: Tests: imported nginx modules tests from nginx-tests.
diffstat: nginx/t/README | 12 + nginx/t/js.t | 391 ++++++++++++++++++++ nginx/t/js_args.t | 167 ++++++++ nginx/t/js_async.t | 225 +++++++++++ nginx/t/js_body_filter.t | 168 ++++++++ nginx/t/js_body_filter_if.t | 127 ++++++ nginx/t/js_buffer.t | 184 +++++++++ nginx/t/js_dump.t | 110 +++++ nginx/t/js_fetch.t | 710 +++++++++++++++++++++++++++++++++++++ nginx/t/js_fetch_https.t | 283 ++++++++++++++ nginx/t/js_fetch_objects.t | 500 ++++++++++++++++++++++++++ nginx/t/js_fetch_resolver.t | 231 ++++++++++++ nginx/t/js_fetch_timeout.t | 119 ++++++ nginx/t/js_fetch_verify.t | 192 ++++++++++ nginx/t/js_header_filter.t | 93 ++++ nginx/t/js_header_filter_if.t | 95 ++++ nginx/t/js_headers.t | 568 +++++++++++++++++++++++++++++ nginx/t/js_import.t | 108 +++++ nginx/t/js_import2.t | 127 ++++++ nginx/t/js_internal_redirect.t | 107 +++++ nginx/t/js_modules.t | 84 ++++ nginx/t/js_ngx.t | 94 ++++ nginx/t/js_object.t | 137 +++++++ nginx/t/js_paths.t | 110 +++++ nginx/t/js_preload_object.t | 181 +++++++++ nginx/t/js_promise.t | 201 ++++++++++ nginx/t/js_request_body.t | 110 +++++ nginx/t/js_return.t | 73 +++ nginx/t/js_subrequests.t | 636 +++++++++++++++++++++++++++++++++ nginx/t/js_var.t | 90 ++++ nginx/t/js_var2.t | 90 ++++ nginx/t/js_variables.t | 95 ++++ nginx/t/stream_js.t | 478 ++++++++++++++++++++++++ nginx/t/stream_js_buffer.t | 177 +++++++++ nginx/t/stream_js_exit.t | 152 +++++++ nginx/t/stream_js_fetch.t | 277 ++++++++++++++ nginx/t/stream_js_fetch_https.t | 404 +++++++++++++++++++++ nginx/t/stream_js_fetch_init.t | 149 +++++++ nginx/t/stream_js_import.t | 117 ++++++ nginx/t/stream_js_import2.t | 117 ++++++ nginx/t/stream_js_ngx.t | 94 ++++ nginx/t/stream_js_object.t | 98 +++++ nginx/t/stream_js_preload_object.t | 122 ++++++ nginx/t/stream_js_send.t | 186 +++++++++ nginx/t/stream_js_var.t | 75 +++ nginx/t/stream_js_var2.t | 75 +++ nginx/t/stream_js_variables.t | 84 ++++ 47 files changed, 9023 insertions(+), 0 deletions(-) diffs (truncated from 9211 to 1000 lines): diff -r e7aedbc18246 -r 08a912ab9520 nginx/t/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nginx/t/README Mon May 22 17:59:47 2023 -0700 @@ -0,0 +1,12 @@ +Test suite for nginx JavaScript module. + +This test suite relies on nginx-tests repository for the test library. + +Use prove to run tests as one usually do for perl tests. Individual tests +may be run as well. + +Usage: + + $ TEST_NGINX_BINARY=/path/to/nginx prove -r -I /path/to/nginx-tests/lib/ nginx/t + +Refer to nginx-tests documentation for more details. diff -r e7aedbc18246 -r 08a912ab9520 nginx/t/js.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nginx/t/js.t Mon May 22 17:59:47 2023 -0700 @@ -0,0 +1,391 @@ +#!/usr/bin/perl + +# (C) Roman Arutyunyan +# (C) Dmitry Volyntsev +# (C) Nginx, Inc. + +# Tests for http njs module. + +############################################################################### + +use warnings; +use strict; + +use Test::More; +use Socket qw/ CRLF /; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/http rewrite/) + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +http { + %%TEST_GLOBALS_HTTP%% + + js_set $test_method test.method; + js_set $test_version test.version; + js_set $test_addr test.addr; + js_set $test_uri test.uri; + js_set $test_var test.variable; + js_set $test_type test.type; + js_set $test_global test.global_obj; + js_set $test_log test.log; + js_set $test_internal test.sub_internal; + js_set $test_except test.except; + + js_import test.js; + + server { + listen 127.0.0.1:8080; + server_name localhost; + + location /njs { + js_content test.njs; + } + + location /method { + return 200 $test_method; + } + + location /version { + return 200 $test_version; + } + + location /addr { + return 200 $test_addr; + } + + location /uri { + return 200 $test_uri; + } + + location /var { + return 200 $test_var; + } + + location /global { + return 200 $test_global; + } + + location /body { + js_content test.request_body; + } + + location /in_file { + client_body_in_file_only on; + js_content test.request_body; + } + + location /status { + js_content test.status; + } + + location /request_body { + js_content test.request_body; + } + + location /request_body_cache { + js_content test.request_body_cache; + } + + location /send { + js_content test.send; + } + + location /return_method { + js_content test.return_method; + } + + location /type { + js_content test.type; + } + + location /log { + return 200 $test_log; + } + + location /internal { + js_content test.internal; + } + + location /sub_internal { + internal; + return 200 $test_internal; + } + + location /except { + return 200 $test_except; + } + + location /content_except { + js_content test.content_except; + } + + location /content_empty { + js_content test.content_empty; + } + } +} + +EOF + +$t->write_file('test.js', <<EOF); + var global = ['n', 'j', 's'].join(""); + + function test_njs(r) { + r.return(200, njs.version); + } + + function method(r) { + return 'method=' + r.method; + } + + function version(r) { + return 'version=' + r.httpVersion; + } + + function addr(r) { + return 'addr=' + r.remoteAddress; + } + + function uri(r) { + return 'uri=' + r.uri; + } + + function variable(r) { + return 'variable=' + r.variables.remote_addr; + } + + function global_obj(r) { + return 'global=' + global; + } + + function status(r) { + r.status = 204; + r.sendHeader(); + r.finish(); + } + + function request_body(r) { + try { + var body = r.requestText; + r.return(200, body); + + } catch (e) { + r.return(500, e.message); + } + } + + function request_body_cache(r) { + function t(v) {return Buffer.isBuffer(v) ? 'buffer' : (typeof v);} + r.return(200, + `requestText:\${t(r.requestText)} requestBuffer:\${t(r.requestBuffer)}`); + } + + function send(r) { + var a, s; + r.status = 200; + r.sendHeader(); + for (a in r.args) { + if (a.substr(0, 3) == 'foo') { + s = r.args[a]; + r.send('n=' + a + ', v=' + s.substr(0, 2) + ' '); + } + } + r.finish(); + } + + function return_method(r) { + r.return(Number(r.args.c), r.args.t); + } + + function type(r) { + var p = r.args.path.split('.').reduce((a, v) => a[v], r); + + var typ = Buffer.isBuffer(p) ? 'buffer' : (typeof p); + r.return(200, `type: \${typ}`); + } + + function log(r) { + r.log('SEE-LOG'); + } + + async function internal(r) { + let reply = await r.subrequest('/sub_internal'); + + r.return(200, `parent: \${r.internal} sub: \${reply.responseText}`); + } + + function sub_internal(r) { + return r.internal; + } + + function except(r) { + var fs = require('fs'); + fs.readFileSync(); + } + + + function content_except(r) { + JSON.parse({}.a.a); + } + + function content_empty(r) { + } + + export default {njs:test_njs, method, version, addr, uri, + variable, global_obj, status, request_body, internal, + request_body_cache, send, return_method, sub_internal, + type, log, except, content_except, content_empty}; + +EOF + +$t->try_run('no njs available')->plan(27); + +############################################################################### + +like(http_get('/method'), qr/method=GET/, 'r.method'); +like(http_get('/version'), qr/version=1.0/, 'r.httpVersion'); +like(http_get('/addr'), qr/addr=127.0.0.1/, 'r.remoteAddress'); +like(http_get('/uri'), qr/uri=\/uri/, 'r.uri'); + +like(http_get('/status'), qr/204 No Content/, 'r.status'); + +like(http_post('/body'), qr/REQ-BODY/, 'request body'); +like(http_post('/in_file'), qr/request body is in a file/, + 'request body in file'); +like(http_post_big('/body'), qr/200.*^(1234567890){1024}$/ms, + 'request body big'); + +like(http_get('/send?foo=12345&n=11&foo-2=bar&ndd=&foo-3=z'), + qr/n=foo, v=12 n=foo-2, v=ba n=foo-3, v=z/, 'r.send'); + +like(http_get('/return_method?c=200'), qr/200 OK.*\x0d\x0a?\x0d\x0a?$/s, + 'return code'); +like(http_get('/return_method?c=200&t=SEE-THIS'), qr/200 OK.*^SEE-THIS$/ms, + 'return text'); +like(http_get('/return_method?c=301&t=path'), qr/ 301 .*Location: path/s, + 'return redirect'); +like(http_get('/return_method?c=404'), qr/404 Not.*html/s, 'return error page'); +like(http_get('/return_method?c=inv'), qr/ 500 /, 'return invalid'); + +like(http_get('/type?path=variables.host'), qr/200 OK.*type: string$/s, + 'variables type'); +like(http_get('/type?path=rawVariables.host'), qr/200 OK.*type: buffer$/s, + 'rawVariables type'); + +like(http_post('/type?path=requestText'), qr/200 OK.*type: string$/s, + 'requestText type'); +like(http_post('/type?path=requestBuffer'), qr/200 OK.*type: buffer$/s, + 'requestBuffer type'); +like(http_post('/request_body_cache'), + qr/requestText:string requestBuffer:buffer$/s, 'request body cache'); + +like(http_get('/var'), qr/variable=127.0.0.1/, 'r.variables'); +like(http_get('/global'), qr/global=njs/, 'global code'); +like(http_get('/log'), qr/200 OK/, 'r.log'); + +TODO: { +local $TODO = 'not yet' unless has_version('0.7.7'); + +like(http_get('/internal'), qr/parent: false sub: true/, 'r.internal'); + +} + +http_get('/except'); +http_get('/content_except'); + +like(http_get('/content_empty'), qr/500 Internal Server Error/, + 'empty handler'); + +$t->stop(); + +ok(index($t->read_file('error.log'), 'SEE-LOG') > 0, 'log js'); +ok(index($t->read_file('error.log'), 'at fs.readFileSync') > 0, + 'js_set backtrace'); +ok(index($t->read_file('error.log'), 'at JSON.parse') > 0, + 'js_content backtrace'); + +############################################################################### + +sub has_version { + my $need = shift; + + http_get('/njs') =~ /^([.0-9]+)$/m; + + my @v = split(/\./, $1); + my ($n, $v); + + for $n (split(/\./, $need)) { + $v = shift @v || 0; + return 0 if $n > $v; + return 1 if $v > $n; + } + + return 1; +} + +############################################################################### + +sub http_get_hdr { + my ($url, %extra) = @_; + return http(<<EOF, %extra); +GET $url HTTP/1.0 +FoO: 12345 + +EOF +} + +sub http_get_ihdr { + my ($url, %extra) = @_; + return http(<<EOF, %extra); +GET $url HTTP/1.0 +foo: 12345 +Host: localhost +foo2: bar +X-xxx: more +foo-3: z + +EOF +} + +sub http_post { + my ($url, %extra) = @_; + + my $p = "POST $url HTTP/1.0" . CRLF . + "Host: localhost" . CRLF . + "Content-Length: 8" . CRLF . + CRLF . + "REQ-BODY"; + + return http($p, %extra); +} + +sub http_post_big { + my ($url, %extra) = @_; + + my $p = "POST $url HTTP/1.0" . CRLF . + "Host: localhost" . CRLF . + "Content-Length: 10240" . CRLF . + CRLF . + ("1234567890" x 1024); + + return http($p, %extra); +} + +############################################################################### diff -r e7aedbc18246 -r 08a912ab9520 nginx/t/js_args.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nginx/t/js_args.t Mon May 22 17:59:47 2023 -0700 @@ -0,0 +1,167 @@ +#!/usr/bin/perl + +# (C) Dmitry Volyntsev +# (C) Nginx, Inc. + +# Tests for http njs module, arguments tests. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +eval { require JSON::PP; }; +plan(skip_all => "JSON::PP not installed") if $@; + +my $t = Test::Nginx->new()->has(qw/http/) + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +http { + %%TEST_GLOBALS_HTTP%% + + js_import test.js; + + js_set $test_iter test.iter; + + server { + listen 127.0.0.1:8080; + server_name localhost; + + location /njs { + js_content test.njs; + } + + location /iter { + return 200 $test_iter; + } + + location /keys { + js_content test.keys; + } + + location /object { + js_content test.object; + } + } +} + +EOF + +$t->write_file('test.js', <<EOF); + function test_njs(r) { + r.return(200, njs.version); + } + + function iter(r) { + var s = '', a; + for (a in r.args) { + if (a.substr(0, 3) == 'foo') { + s += r.args[a]; + } + } + + return s; + } + + function keys(r) { + r.return(200, Object.keys(r.args).sort()); + } + + function object(r) { + r.return(200, JSON.stringify(r.args)); + } + + export default {njs: test_njs, iter, keys, object}; + +EOF + +$t->try_run('no njs')->plan(15); + +############################################################################### + +sub recode { + my $json; + eval { $json = JSON::PP::decode_json(shift) }; + + if ($@) { + return "<failed to parse JSON>"; + } + + JSON::PP->new()->canonical()->encode($json); +} + +sub get_json { + http_get(shift) =~ /\x0d\x0a?\x0d\x0a?(.*)/ms; + recode($1); +} + +############################################################################### + +local $TODO = 'not yet' unless has_version('0.7.6'); + +like(http_get('/iter?foo=12345&foo2=bar&nn=22&foo-3=z'), qr/12345barz/, + 'r.args iteration'); +like(http_get('/iter?foo=123&foo2=&foo3&foo4=456'), qr/123456/, + 'r.args iteration 2'); +like(http_get('/iter?foo=123&foo2=&foo3'), qr/123/, 'r.args iteration 3'); +like(http_get('/iter?foo=123&foo2='), qr/123/, 'r.args iteration 4'); +like(http_get('/iter?foo=1&foo=2'), qr/1,2/m, 'r.args iteration 5'); + +like(http_get('/keys?b=1&c=2&a=5'), qr/a,b,c/m, 'r.args sorted keys'); +like(http_get('/keys?b=1&b=2'), qr/b/m, 'r.args duplicate keys'); +like(http_get('/keys?b=1&a&c='), qr/a,b,c/m, 'r.args empty value'); + +is(get_json('/object'), '{}', 'empty object'); +is(get_json('/object?a=1&b=2&c=3'), '{"a":"1","b":"2","c":"3"}', + 'ordinary object'); +is(get_json('/object?a=1&A=2'), '{"A":"2","a":"1"}', + 'case sensitive object'); +is(get_json('/object?a=1&A=2&a=3'), '{"A":"2","a":["1","3"]}', + 'duplicate keys object'); +is(get_json('/object?%61=1&a=2'), '{"a":["1","2"]}', + 'keys percent-encoded object'); +is(get_json('/object?a=%62%63&b=%63%64'), '{"a":"bc","b":"cd"}', + 'values percent-encoded object'); +is(get_json('/object?a=%6&b=%&c=%%&d=%zz'), + '{"a":"%6","b":"%","c":"%%","d":"%zz"}', + 'values percent-encoded broken object'); + +############################################################################### + +sub has_version { + my $need = shift; + + http_get('/njs') =~ /^([.0-9]+)$/m; + + my @v = split(/\./, $1); + my ($n, $v); + + for $n (split(/\./, $need)) { + $v = shift @v || 0; + return 0 if $n > $v; + return 1 if $v > $n; + } + + return 1; +} + +############################################################################### diff -r e7aedbc18246 -r 08a912ab9520 nginx/t/js_async.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nginx/t/js_async.t Mon May 22 17:59:47 2023 -0700 @@ -0,0 +1,225 @@ +#!/usr/bin/perl + +# (C) Dmitry Volyntsev +# (C) Nginx, Inc. + +# Async tests for http njs module. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/http rewrite/) + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +http { + %%TEST_GLOBALS_HTTP%% + + js_set $test_async test.set_timeout; + js_set $context_var test.context_var; + js_set $test_set_rv_var test.set_rv_var; + + js_import test.js; + + server { + listen 127.0.0.1:8080; + server_name localhost; + + location /njs { + js_content test.njs; + } + + location /async_var { + return 200 $test_async; + } + + location /shared_ctx { + add_header H $context_var; + js_content test.shared_ctx; + } + + location /set_timeout { + js_content test.set_timeout; + } + + location /set_timeout_many { + js_content test.set_timeout_many; + } + + location /set_timeout_data { + postpone_output 0; + js_content test.set_timeout_data; + } + + location /limit_rate { + postpone_output 0; + sendfile_max_chunk 5; + js_content test.limit_rate; + } + + location /async_content { + js_content test.async_content; + } + + location /set_rv_var { + return 200 $test_set_rv_var; + } + } +} + +EOF + +$t->write_file('test.js', <<EOF); + function test_njs(r) { + r.return(200, njs.version); + } + + function set_timeout(r) { + var timerId = setTimeout(timeout_cb_r, 5, r, 0); + clearTimeout(timerId); + setTimeout(timeout_cb_r, 5, r, 0) + } + + function set_timeout_data(r) { + setTimeout(timeout_cb_data, 5, r, 0); + } + + function set_timeout_many(r) { + for (var i = 0; i < 5; i++) { + setTimeout(timeout_cb_empty, 5, r, i); + } + + setTimeout(timeout_cb_reply, 10, r); + } + + function timeout_cb_r(r, cnt) { + if (cnt == 10) { + r.status = 200; + r.headersOut['Content-Type'] = 'foo'; + r.sendHeader(); + r.finish(); + + } else { + setTimeout(timeout_cb_r, 5, r, ++cnt); + } + } + + function timeout_cb_empty(r, arg) { + r.log("timeout_cb_empty" + arg); + } + + function timeout_cb_reply(r) { + r.status = 200; + r.headersOut['Content-Type'] = 'reply'; + r.sendHeader(); + r.finish(); + } + + function timeout_cb_data(r, counter) { + if (counter == 0) { + r.log("timeout_cb_data: init"); + r.status = 200; + r.sendHeader(); + setTimeout(timeout_cb_data, 5, r, ++counter); + + } else if (counter == 10) { + r.log("timeout_cb_data: finish"); + r.finish(); + + } else { + r.send("" + counter); + setTimeout(timeout_cb_data, 5, r, ++counter); + } + } + + var js_; + function context_var() { + return js_; + } + + function shared_ctx(r) { + js_ = r.variables.arg_a; + + r.status = 200; + r.sendHeader(); + r.finish(); + } + + function limit_rate_cb(r) { + r.finish(); + } + + function limit_rate(r) { + r.status = 200; + r.sendHeader(); + r.send("AAAAA".repeat(10)) + setTimeout(limit_rate_cb, 1000, r); + } + + function pr(x) { + return new Promise(resolve => {resolve(x)}).then(v => v).then(v => v); + } + + async function async_content(r) { + const a1 = await pr('A'); + const a2 = await pr('B'); + + r.return(200, `retval: \${a1 + a2}`); + } + + async function set_rv_var(r) { + const a1 = await pr(10); + const a2 = await pr(20); + + r.setReturnValue(`retval: \${a1 + a2}`); + } + + export default {njs:test_njs, set_timeout, set_timeout_data, + set_timeout_many, context_var, shared_ctx, limit_rate, + async_content, set_rv_var}; + +EOF + +$t->try_run('no njs available')->plan(9); + +############################################################################### + +like(http_get('/set_timeout'), qr/Content-Type: foo/, 'setTimeout'); +like(http_get('/set_timeout_many'), qr/Content-Type: reply/, 'setTimeout many'); +like(http_get('/set_timeout_data'), qr/123456789/, 'setTimeout data'); +like(http_get('/shared_ctx?a=xxx'), qr/H: xxx/, 'shared context'); +like(http_get('/limit_rate'), qr/A{50}/, 'limit_rate'); + +like(http_get('/async_content'), qr/retval: AB/, 'async content'); +like(http_get('/set_rv_var'), qr/retval: 30/, 'set return value variable'); + +http_get('/async_var'); + +$t->stop(); + +ok(index($t->read_file('error.log'), 'pending events') > 0, + 'pending js events'); +ok(index($t->read_file('error.log'), 'async operation inside') > 0, + 'async op in var handler'); + +############################################################################### diff -r e7aedbc18246 -r 08a912ab9520 nginx/t/js_body_filter.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nginx/t/js_body_filter.t Mon May 22 17:59:47 2023 -0700 @@ -0,0 +1,168 @@ +#!/usr/bin/perl + +# (C) Dmitry Volyntsev +# (C) Nginx, Inc. + +# Tests for http njs module, body filter. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/http proxy/) + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +http { + %%TEST_GLOBALS_HTTP%% + + js_import test.js; + + server { + listen 127.0.0.1:8080; + server_name localhost; + + location /njs { + js_content test.njs; + } + + location /append { + js_body_filter test.append; + proxy_pass http://127.0.0.1:8081/source; + } + + location /buffer_type { + js_body_filter test.buffer_type buffer_type=buffer; + proxy_pass http://127.0.0.1:8081/source; + } + + location /forward { + js_body_filter test.forward buffer_type=string; + proxy_pass http://127.0.0.1:8081/source; + } + + location /filter { + proxy_buffering off; + js_body_filter test.filter; + proxy_pass http://127.0.0.1:8081/source; + } + + location /prepend { + js_body_filter test.prepend; + proxy_pass http://127.0.0.1:8081/source; + } + } + + server { + listen 127.0.0.1:8081; + server_name localhost; + + location /source { + postpone_output 1; + js_content test.source; + } + } +} + +EOF + +$t->write_file('test.js', <<EOF); + function test_njs(r) { + r.return(200, njs.version); + } + + function append(r, data, flags) { + r.sendBuffer(data, {last:false}); + + if (flags.last) { + r.sendBuffer("XXX", flags); + } + } + + var collect = Buffer.from([]); + function buffer_type(r, data, flags) { + collect = Buffer.concat([collect, data]); + + if (flags.last) { + r.sendBuffer(collect, flags); + } + } + + function chain(chunks, i) { + if (i < chunks.length) { + chunks.r.send(chunks[i++]); + setTimeout(chunks.chain, chunks.delay, chunks, i); + + } else { + chunks.r.finish(); + } + } + + function source(r) { + var chunks = ['AAA', 'BB', 'C', 'DDDD']; + chunks.delay = 5; + chunks.r = r; + chunks.chain = chain; + + r.status = 200; + r.sendHeader(); + chain(chunks, 0); + } + + function filter(r, data, flags) { + if (flags.last || data.length >= Number(r.args.len)) { + r.sendBuffer(`\${data}|`, flags); + + if (r.args.dup && !flags.last) { + r.sendBuffer(data, flags); + } + } + } + + function forward(r, data, flags) { + r.sendBuffer(data, flags); + } + + function prepend(r, data, flags) { + r.sendBuffer("XXX"); + r.sendBuffer(data, flags); + r.done(); + } + + export default {njs: test_njs, append, buffer_type, filter, forward, + prepend, source}; + +EOF + +$t->try_run('no njs body filter')->plan(6); + +############################################################################### + +like(http_get('/append'), qr/AAABBCDDDDXXX/, 'append'); +like(http_get('/buffer_type'), qr/AAABBCDDDD/, 'buffer type'); +like(http_get('/forward'), qr/AAABBCDDDD/, 'forward'); +like(http_get('/filter?len=3'), qr/AAA|DDDD|/, 'filter 3'); +like(http_get('/filter?len=2&dup=1'), qr/AAA|AAABB|BBDDDD|DDDD/, + 'filter 2 dup'); +like(http_get('/prepend'), qr/XXXAAABBCDDDD/, 'prepend'); + +############################################################################### diff -r e7aedbc18246 -r 08a912ab9520 nginx/t/js_body_filter_if.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nginx/t/js_body_filter_if.t Mon May 22 17:59:47 2023 -0700 @@ -0,0 +1,127 @@ +#!/usr/bin/perl + +# (C) Dmitry Volyntsev +# (C) Nginx, Inc. + +# Tests for http njs module, body filter, if context. + +############################################################################### + +use warnings; +use strict; + +use Test::More; _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel