Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split periodic tests #858

Merged
merged 3 commits into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion nginx/ngx_http_js_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ static ngx_http_request_t *ngx_http_qjs_request(JSValueConst val);
static JSValue ngx_http_qjs_request_make(JSContext *cx, ngx_int_t proto_id,
ngx_http_request_t *r);
static void ngx_http_qjs_request_finalizer(JSRuntime *rt, JSValue val);
static void ngx_http_qjs_periodic_finalizer(JSRuntime *rt, JSValue val);
#endif

static ngx_pool_t *ngx_http_js_pool(ngx_http_request_t *r);
Expand Down Expand Up @@ -1097,7 +1098,7 @@ static JSClassDef ngx_http_qjs_request_class = {

static JSClassDef ngx_http_qjs_periodic_class = {
"PeriodicSession",
.finalizer = NULL,
.finalizer = ngx_http_qjs_periodic_finalizer,
};


Expand Down Expand Up @@ -7553,6 +7554,20 @@ ngx_http_qjs_request_finalizer(JSRuntime *rt, JSValue val)
}


static void
ngx_http_qjs_periodic_finalizer(JSRuntime *rt, JSValue val)
{
ngx_http_qjs_request_t *req;

req = JS_GetOpaque(val, NGX_QJS_CLASS_ID_HTTP_PERIODIC);
if (req == NULL) {
return;
}

js_free_rt(rt, req);
}


static ngx_engine_t *
ngx_engine_qjs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf,
njs_int_t proto_id, void *external)
Expand Down
5 changes: 4 additions & 1 deletion nginx/ngx_js_shared_dict.c
Original file line number Diff line number Diff line change
Expand Up @@ -2219,7 +2219,10 @@ ngx_qjs_ext_shared_dict_incr(JSContext *cx, JSValueConst this_val,
return JS_EXCEPTION;
}

if (JS_ToFloat64(cx, &init, argv[2]) < 0) {
if (JS_IsUndefined(argv[2])) {
init = 0;

} else if (JS_ToFloat64(cx, &init, argv[2]) < 0) {
return JS_EXCEPTION;
}

Expand Down
17 changes: 16 additions & 1 deletion nginx/ngx_stream_js_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ static ngx_stream_session_t *ngx_stream_qjs_session(JSValueConst val);
static JSValue ngx_stream_qjs_session_make(JSContext *cx, ngx_int_t proto_id,
ngx_stream_session_t *s);
static void ngx_stream_qjs_session_finalizer(JSRuntime *rt, JSValue val);
static void ngx_stream_qjs_periodic_finalizer(JSRuntime *rt, JSValue val);

#endif

Expand Down Expand Up @@ -813,7 +814,7 @@ static JSClassDef ngx_stream_qjs_session_class = {

static JSClassDef ngx_stream_qjs_periodic_class = {
"Periodic",
.finalizer = NULL,
.finalizer = ngx_stream_qjs_periodic_finalizer,
};


Expand Down Expand Up @@ -2812,6 +2813,20 @@ ngx_stream_qjs_session_finalizer(JSRuntime *rt, JSValue val)
}


static void
ngx_stream_qjs_periodic_finalizer(JSRuntime *rt, JSValue val)
{
ngx_stream_qjs_session_t *ses;

ses = JS_GetOpaque(val, NGX_QJS_CLASS_ID_STREAM_PERIODIC);
if (ses == NULL) {
return;
}

js_free_rt(rt, ses);
}


static ngx_engine_t *
ngx_engine_qjs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf,
njs_int_t proto_id, void *external)
Expand Down
92 changes: 3 additions & 89 deletions nginx/t/js_periodic.t
Original file line number Diff line number Diff line change
Expand Up @@ -59,46 +59,18 @@ http {
js_periodic test.tick interval=30ms jitter=1ms;
js_periodic test.timer interval=1s worker_affinity=all;
js_periodic test.overrun interval=30ms;
js_periodic test.file interval=1s;
js_periodic test.fetch interval=40ms;
js_periodic test.multiple_fetches interval=1s;
js_periodic test.affinity interval=50ms worker_affinity=0101;
js_periodic test.vars interval=10s;

js_periodic test.fetch_exception interval=1s;
js_periodic test.tick_exception interval=1s;
js_periodic test.timer_exception interval=1s;
js_periodic test.timeout_exception interval=30ms;
}

location /engine {
js_content test.engine;
}

location /fetch_ok {
return 200 'ok';
}

location /fetch_foo {
return 200 'foo';
}

location /test_affinity {
js_content test.test_affinity;
}

location /test_fetch {
js_content test.test_fetch;
}

location /test_file {
js_content test.test_file;
}

location /test_multiple_fetches {
js_content test.test_multiple_fetches;
}

location /test_tick {
js_content test.test_tick;
}
Expand All @@ -119,51 +91,15 @@ http {

EOF

my $p0 = port(8080);

$t->write_file('test.js', <<EOF);
import fs from 'fs';

function engine(r) {
r.return(200, njs.engine);
}

function affinity() {
ngx.shared.workers.set(ngx.worker_id, 1);
}

async function fetch() {
let reply = await ngx.fetch('http://127.0.0.1:$p0/fetch_ok');
let body = await reply.text();

let v = ngx.shared.strings.get('fetch') || '';
ngx.shared.strings.set('fetch', v + body);
}

function js_set() {
return 'JS-SET';
}

async function multiple_fetches() {
let reply = await ngx.fetch('http://127.0.0.1:$p0/fetch_ok');
let reply2 = await ngx.fetch('http://127.0.0.1:$p0/fetch_foo');
let body = await reply.text();
let body2 = await reply2.text();

ngx.shared.strings.set('multiple_fetches', body + '\@' + body2);
}

async function fetch_exception() {
let reply = await ngx.fetch('garbage');
}

async function file() {
let fh = await fs.promises.open(ngx.conf_prefix + 'file', 'a+');

await fh.write('abc');
await fh.close();
}

async function overrun() {
setTimeout(() => {}, 100000);
}
Expand Down Expand Up @@ -214,20 +150,6 @@ $t->write_file('test.js', <<EOF);
r.return(200, `[\${ngx.shared.workers.keys().toSorted()}]`);
}

function test_fetch(r) {
r.return(200, ngx.shared.strings.get('fetch').startsWith('okok'));
}

function test_file(r) {
r.return(200,
fs.readFileSync(ngx.conf_prefix + 'file').toString() == 'abc');
}

function test_multiple_fetches(r) {
r.return(200, ngx.shared.strings.get('multiple_fetches')
.startsWith('ok\@foo'));
}

function test_tick(r) {
r.return(200, ngx.shared.nums.get('tick') >= 3);
}
Expand All @@ -244,19 +166,14 @@ $t->write_file('test.js', <<EOF);
r.return(200, ngx.shared.strings.get('vars'));
}

export default { affinity, fetch, fetch_exception, file, js_set,
multiple_fetches, overrun, vars, test_affinity, test_fetch,
test_file, test_multiple_fetches, test_tick,
export default { affinity, js_set, overrun, vars, test_affinity, test_tick,
test_timeout_exception, test_timer, test_vars, tick,
tick_exception, timer, timer_exception,
timeout_exception, engine };
tick_exception, timer, timer_exception, timeout_exception };
EOF

$t->try_run('no js_periodic');

plan(skip_all => 'not yet') if http_get('/engine') =~ /QuickJS$/m;

$t->plan(9);
$t->plan(6);

###############################################################################

Expand All @@ -265,9 +182,6 @@ select undef, undef, undef, 0.1;
like(http_get('/test_affinity'), qr/\[1,3]/, 'affinity test');
like(http_get('/test_tick'), qr/true/, '3x tick test');
like(http_get('/test_timer'), qr/true/, 'timer test');
like(http_get('/test_file'), qr/true/, 'file test');
like(http_get('/test_fetch'), qr/true/, 'periodic fetch test');
like(http_get('/test_multiple_fetches'), qr/true/, 'multiple fetch test');

like(http_get('/test_timeout_exception'), qr/true/, 'timeout exception test');
like(http_get('/test_vars'), qr/JS-VAR\|JS-SET\|MAP-VAR/, 'vars test');
Expand Down
138 changes: 138 additions & 0 deletions nginx/t/js_periodic_fetch.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#!/usr/bin/perl

# (C) Dmitry Volyntsev
# (C) Nginx, Inc.

# Tests for js_periodic directive.

###############################################################################

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;
worker_processes 4;

events {
}

worker_shutdown_timeout 100ms;

http {
%%TEST_GLOBALS_HTTP%%

js_import test.js;

js_shared_dict_zone zone=strings:32k;

server {
listen 127.0.0.1:8080;
server_name localhost;

location @periodic {
js_periodic test.fetch interval=40ms;
js_periodic test.multiple_fetches interval=1s;

js_periodic test.fetch_exception interval=1s;
}

location /engine {
js_content test.engine;
}

location /fetch_ok {
return 200 'ok';
}

location /fetch_foo {
return 200 'foo';
}

location /test_fetch {
js_content test.test_fetch;
}

location /test_multiple_fetches {
js_content test.test_multiple_fetches;
}
}
}

EOF

my $p0 = port(8080);

$t->write_file('test.js', <<EOF);
function engine(r) {
r.return(200, njs.engine);
}

async function fetch() {
let reply = await ngx.fetch('http://127.0.0.1:$p0/fetch_ok');
let body = await reply.text();

let v = ngx.shared.strings.get('fetch') || '';
ngx.shared.strings.set('fetch', v + body);
}

async function multiple_fetches() {
let reply = await ngx.fetch('http://127.0.0.1:$p0/fetch_ok');
let reply2 = await ngx.fetch('http://127.0.0.1:$p0/fetch_foo');
let body = await reply.text();
let body2 = await reply2.text();

ngx.shared.strings.set('multiple_fetches', body + '\@' + body2);
}

async function fetch_exception() {
let reply = await ngx.fetch('garbage');
}

function test_fetch(r) {
r.return(200, ngx.shared.strings.get('fetch').startsWith('okok'));
}

function test_multiple_fetches(r) {
r.return(200, ngx.shared.strings.get('multiple_fetches')
.startsWith('ok\@foo'));
}

export default { fetch, fetch_exception, multiple_fetches, test_fetch,
test_multiple_fetches, engine };
EOF

$t->try_run('no js_periodic with fetch');

plan(skip_all => 'not yet') if http_get('/engine') =~ /QuickJS$/m;

$t->plan(3);

###############################################################################

select undef, undef, undef, 0.1;

like(http_get('/test_fetch'), qr/true/, 'periodic fetch test');
like(http_get('/test_multiple_fetches'), qr/true/, 'multiple fetch test');

$t->stop();

unlike($t->read_file('error.log'), qr/\[error\].*should not be seen/,
'check for not discadred events');
Loading