[njs] Tests: added async tests support.

Dmitry Volyntsev xeioex at nginx.com
Fri Oct 8 13:51:17 UTC 2021


details:   https://hg.nginx.org/njs/rev/839307cc293a
branches:  
changeset: 1718:839307cc293a
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Fri Oct 08 13:50:50 2021 +0000
description:
Tests: added async tests support.

diffstat:

 src/njs.h                     |    2 +
 src/njs_value.c               |   14 +
 src/test/njs_externals_test.c |  150 ++++++++++++++
 src/test/njs_externals_test.h |   19 +
 src/test/njs_unit_test.c      |  424 +++++++++++++++++++++++++++++++++++------
 5 files changed, 547 insertions(+), 62 deletions(-)

diffs (798 lines):

diff -r fb3e13959b71 -r 839307cc293a src/njs.h
--- a/src/njs.h	Fri Oct 08 13:41:01 2021 +0000
+++ b/src/njs.h	Fri Oct 08 13:50:50 2021 +0000
@@ -380,6 +380,7 @@ NJS_EXPORT void njs_vm_memory_error(njs_
 
 NJS_EXPORT void njs_value_undefined_set(njs_value_t *value);
 NJS_EXPORT void njs_value_null_set(njs_value_t *value);
+NJS_EXPORT void njs_value_invalid_set(njs_value_t *value);
 NJS_EXPORT void njs_value_boolean_set(njs_value_t *value, int yn);
 NJS_EXPORT void njs_value_number_set(njs_value_t *value, double num);
 
@@ -396,6 +397,7 @@ NJS_EXPORT njs_int_t njs_vm_prop_name(nj
 NJS_EXPORT njs_int_t njs_value_is_null(const njs_value_t *value);
 NJS_EXPORT njs_int_t njs_value_is_undefined(const njs_value_t *value);
 NJS_EXPORT njs_int_t njs_value_is_null_or_undefined(const njs_value_t *value);
+NJS_EXPORT njs_int_t njs_value_is_valid(const njs_value_t *value);
 NJS_EXPORT njs_int_t njs_value_is_boolean(const njs_value_t *value);
 NJS_EXPORT njs_int_t njs_value_is_number(const njs_value_t *value);
 NJS_EXPORT njs_int_t njs_value_is_valid_number(const njs_value_t *value);
diff -r fb3e13959b71 -r 839307cc293a src/njs_value.c
--- a/src/njs_value.c	Fri Oct 08 13:41:01 2021 +0000
+++ b/src/njs_value.c	Fri Oct 08 13:50:50 2021 +0000
@@ -395,6 +395,13 @@ njs_value_null_set(njs_value_t *value)
 
 
 void
+njs_value_invalid_set(njs_value_t *value)
+{
+    njs_set_invalid(value);
+}
+
+
+void
 njs_value_boolean_set(njs_value_t *value, int yn)
 {
     njs_set_boolean(value, yn);
@@ -451,6 +458,13 @@ njs_value_is_null_or_undefined(const njs
 
 
 njs_int_t
+njs_value_is_valid(const njs_value_t *value)
+{
+    return njs_is_valid(value);
+}
+
+
+njs_int_t
 njs_value_is_boolean(const njs_value_t *value)
 {
     return njs_is_boolean(value);
diff -r fb3e13959b71 -r 839307cc293a src/test/njs_externals_test.c
--- a/src/test/njs_externals_test.c	Fri Oct 08 13:41:01 2021 +0000
+++ b/src/test/njs_externals_test.c	Fri Oct 08 13:50:50 2021 +0000
@@ -373,6 +373,71 @@ njs_unit_test_r_method(njs_vm_t *vm, njs
 
 
 static njs_int_t
+njs_unit_test_r_subrequest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t unused)
+{
+    njs_vm_event_t       vm_event;
+    njs_function_t       *callback;
+    njs_external_ev_t    *ev;
+    njs_external_env_t   *env;
+    njs_unit_test_req_t  *r;
+
+    r = njs_vm_external(vm, njs_external_r_proto_id, njs_argument(args, 0));
+    if (r == NULL) {
+        njs_type_error(vm, "\"this\" is not an external");
+        return NJS_ERROR;
+    }
+
+    callback = njs_value_function(njs_arg(args, nargs, 1));
+    if (callback == NULL) {
+        njs_type_error(vm, "argument is not callable");
+        return NJS_ERROR;
+    }
+
+    vm_event = njs_vm_add_event(vm, callback, 1, NULL, NULL);
+    if (vm_event == NULL) {
+        njs_internal_error(vm, "njs_vm_add_event() failed");
+        return NJS_ERROR;
+    }
+
+    ev = njs_mp_alloc(vm->mem_pool, sizeof(njs_external_ev_t));
+    if (ev == NULL) {
+        njs_memory_error(vm);
+        return NJS_ERROR;
+    }
+
+    ev->vm_event = vm_event;
+    ev->data = r;
+    ev->nargs = 1;
+    njs_value_assign(&ev->args[0], njs_argument(args, 0));
+
+    env = vm->external;
+
+    njs_queue_insert_tail(&env->events, &ev->link);
+
+    njs_set_undefined(&vm->retval);
+
+    return NJS_OK;
+}
+
+
+static njs_int_t
+njs_unit_test_r_retval(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t unused)
+{
+    njs_external_env_t  *env;
+
+    env = vm->external;
+
+    njs_value_assign(&env->retval, njs_arg(args, nargs, 1));
+
+    njs_set_undefined(&vm->retval);
+
+    return NJS_OK;
+}
+
+
+static njs_int_t
 njs_unit_test_r_create(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
@@ -583,6 +648,28 @@ static njs_external_t  njs_unit_test_r_e
     },
 
     {
+        .flags = NJS_EXTERN_METHOD,
+        .name.string = njs_str("subrequest"),
+        .writable = 1,
+        .configurable = 1,
+        .enumerable = 1,
+        .u.method = {
+            .native = njs_unit_test_r_subrequest,
+        }
+    },
+
+    {
+        .flags = NJS_EXTERN_METHOD,
+        .name.string = njs_str("retval"),
+        .writable = 1,
+        .configurable = 1,
+        .enumerable = 1,
+        .u.method = {
+            .native = njs_unit_test_r_retval,
+        }
+    },
+
+    {
         .flags = NJS_EXTERN_OBJECT,
         .name.string = njs_str("props"),
         .enumerable = 1,
@@ -755,3 +842,66 @@ njs_externals_init(njs_vm_t *vm)
 {
     return njs_externals_init_internal(vm, &njs_test_requests[1], 3, 0);
 }
+
+
+njs_int_t
+njs_external_env_init(njs_external_env_t *env)
+{
+    if (env != NULL) {
+        njs_value_invalid_set(&env->retval);
+        njs_queue_init(&env->events);
+    }
+
+    return NJS_OK;
+}
+
+
+njs_int_t
+njs_external_process_events(njs_vm_t *vm, njs_external_env_t *env)
+{
+    njs_queue_t        *events;
+    njs_queue_link_t   *link;
+    njs_external_ev_t  *ev;
+
+    events = &env->events;
+
+    for ( ;; ) {
+        link = njs_queue_first(events);
+
+        if (link == njs_queue_tail(events)) {
+            break;
+        }
+
+        ev = njs_queue_link_data(link, njs_external_ev_t, link);
+
+        njs_queue_remove(&ev->link);
+        ev->link.prev = NULL;
+        ev->link.next = NULL;
+
+        njs_vm_post_event(vm, ev->vm_event, &ev->args[0], ev->nargs);
+    }
+
+    return NJS_OK;
+}
+
+
+njs_int_t
+njs_external_call(njs_vm_t *vm, const njs_str_t *fname, njs_value_t *args,
+    njs_uint_t nargs)
+{
+    njs_int_t       ret;
+    njs_function_t  *func;
+
+    func = njs_vm_function(vm, fname);
+    if (func == NULL) {
+        njs_stderror("njs_external_call(): function \"%V\" not found\n", fname);
+        return NJS_ERROR;
+    }
+
+    ret = njs_vm_call(vm, func, args, nargs);
+    if (ret == NJS_ERROR) {
+        return NJS_ERROR;
+    }
+
+    return njs_vm_run(vm);
+}
diff -r fb3e13959b71 -r 839307cc293a src/test/njs_externals_test.h
--- a/src/test/njs_externals_test.h	Fri Oct 08 13:41:01 2021 +0000
+++ b/src/test/njs_externals_test.h	Fri Oct 08 13:50:50 2021 +0000
@@ -8,8 +8,27 @@
 #define _NJS_EXTERNALS_TEST_H_INCLUDED_
 
 
+typedef struct {
+    njs_value_t             retval;
+    njs_queue_t             events;  /* of njs_external_ev_t */
+} njs_external_env_t;
+
+
+typedef struct {
+    njs_vm_event_t          vm_event;
+    void                    *data;
+    njs_uint_t              nargs;
+    njs_value_t             args[3];
+    njs_queue_link_t        link;
+} njs_external_ev_t;
+
+
 njs_int_t njs_externals_shared_init(njs_vm_t *vm);
 njs_int_t njs_externals_init(njs_vm_t *vm);
+njs_int_t njs_external_env_init(njs_external_env_t *env);
+njs_int_t njs_external_call(njs_vm_t *vm, const njs_str_t *fname,
+    njs_value_t *args, njs_uint_t nargs);
+njs_int_t njs_external_process_events(njs_vm_t *vm, njs_external_env_t *env);
 
 
 #endif /* _NJS_EXTERNALS_TEST_H_INCLUDED_ */
diff -r fb3e13959b71 -r 839307cc293a src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Fri Oct 08 13:41:01 2021 +0000
+++ b/src/test/njs_unit_test.c	Fri Oct 08 13:50:50 2021 +0000
@@ -20486,14 +20486,6 @@ static njs_unit_test_t  njs_test[] =
               "new ctor();"),
       njs_str("[object AsyncFunction]") },
 
-    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
-              "let f = new ctor(); f()"),
-      njs_str("[object Promise]") },
-
-    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
-              "let f = new ctor('x', 'await 1; return x'); f(1)"),
-      njs_str("[object Promise]") },
-
     { njs_str("let f = new Function('x', 'await 1; return x'); f(1)"),
       njs_str("SyntaxError: await is only valid in async functions in runtime:1") },
 
@@ -20510,9 +20502,6 @@ static njs_unit_test_t  njs_test[] =
               "(async function() {f(await 111)})"),
       njs_str("SyntaxError: await in arguments not supported in 1") },
 
-    { njs_str("Promise.all([async () => [await x('X')]])"),
-      njs_str("[object Promise]") },
-
     { njs_str("async () => [await x(1)(),]; async () => [await x(1)()]"),
       njs_str("[object AsyncFunction]") },
 
@@ -20937,8 +20926,59 @@ static njs_unit_test_t  njs_externals_te
 
     { njs_str("$r.buffer instanceof Buffer"),
       njs_str("true") },
+
+    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
+              "let f = new ctor();"
+              "$r.retval(f())"),
+      njs_str("[object Promise]") },
+
+    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
+              "let f = new ctor('x', 'await 1; return x');"
+              "$r.retval(f(1))"),
+      njs_str("[object Promise]") },
+
+    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
+              "let f = new ctor('x', 'await 1; return x');"
+              "f(1).then($r.retval)"),
+      njs_str("1") },
+
+    { njs_str("$r.retval(Promise.all([async () => [await x('X')]]))"),
+      njs_str("[object Promise]") },
+
+    { njs_str("let obj = { a: 1, b: 2};"
+              "function cb(r) { r.retval(obj.a); }"
+              "$r.subrequest(reply => cb(reply))"),
+      njs_str("1") },
 };
 
+
+static njs_unit_test_t  njs_async_handler_test[] =
+{
+    { njs_str("globalThis.main = (function() {"
+              "     function cb(r) { r.retval(1); }"
+              "     function handler(r) {"
+              "         r.subrequest(reply => cb(reply));"
+              "     };"
+              "     return {handler};"
+              "})();"
+              ),
+      njs_str("1") },
+
+#if 0 /* FIXME */
+    { njs_str("globalThis.main = (function() {"
+              "     let obj = { a: 1, b: 2};"
+              "     function cb(r) { r.retval(obj.a); }"
+              "     function handler(r) {"
+              "         r.subrequest(reply => cb(reply));"
+              "     };"
+              "     return {handler};"
+              "})();"
+              ),
+      njs_str("1") },
+#endif
+};
+
+
 static njs_unit_test_t  njs_shared_test[] =
 {
     { njs_str("var cr = require('crypto'); cr.createHash"),
@@ -21531,6 +21571,9 @@ typedef struct {
     njs_uint_t  repeat;
     njs_bool_t  unsafe;
     njs_bool_t  backtrace;
+    njs_bool_t  handler;
+    njs_bool_t  async;
+    unsigned    seed;
 } njs_opts_t;
 
 
@@ -21540,6 +21583,27 @@ typedef struct {
 } njs_stat_t;
 
 
+typedef struct {
+    njs_vm_t            *vm;
+    njs_external_env_t  *env;
+    njs_external_env_t  env0;
+
+    enum {
+        sw_start = 0,
+        sw_handler,
+        sw_loop,
+        sw_done
+    }                   state;
+} njs_external_state_t;
+
+
+typedef struct {
+    njs_external_state_t  *states;
+    njs_uint_t            size;
+    njs_uint_t            current;
+} njs_runtime_t;
+
+
 static void
 njs_unit_test_report(njs_str_t *name, njs_stat_t *prev, njs_stat_t *current)
 {
@@ -21555,20 +21619,240 @@ njs_unit_test_report(njs_str_t *name, nj
 
 
 static njs_int_t
+njs_external_state_init(njs_vm_t *vm, njs_external_state_t *s, njs_opts_t *opts)
+{
+    njs_int_t  ret;
+
+    if (opts->externals) {
+        s->env = &s->env0;
+
+        ret = njs_external_env_init(s->env);
+        if (ret != NJS_OK) {
+            njs_stderror("njs_external_env_init() failed\n");
+            return NJS_ERROR;
+        }
+
+    } else {
+        s->env = NULL;
+    }
+
+    s->vm = njs_vm_clone(vm, s->env);
+    if (s->vm == NULL) {
+        njs_stderror("njs_vm_clone() failed\n");
+        return NJS_ERROR;
+    }
+
+    if (opts->externals) {
+        ret = njs_externals_init(s->vm);
+        if (ret != NJS_OK) {
+            njs_stderror("njs_externals_init() failed\n");
+            return NJS_ERROR;
+        }
+    }
+
+    s->state = sw_start;
+
+    return NJS_OK;
+}
+
+
+static njs_int_t
+njs_external_retval(njs_external_state_t *state, njs_str_t *s)
+{
+    if (state->env != NULL && njs_value_is_valid(&state->env->retval)) {
+        return njs_vm_value_string(state->vm, s, &state->env->retval);
+    }
+
+    return njs_vm_retval_string(state->vm, s);
+}
+
+
+static njs_runtime_t *
+njs_runtime_init(njs_vm_t *vm, njs_opts_t *opts)
+{
+    njs_int_t      ret;
+    njs_uint_t     i;
+    njs_runtime_t  *rt;
+
+    rt = njs_mp_alloc(vm->mem_pool, sizeof(njs_runtime_t));
+    if (rt == NULL) {
+        return NULL;
+    }
+
+    rt->size = opts->repeat;
+    rt->states = njs_mp_alloc(vm->mem_pool,
+                              sizeof(njs_external_state_t) * rt->size);
+    if (rt->states == NULL) {
+        return NULL;
+    }
+
+    rt->current = 0;
+    srandom(opts->seed);
+
+    for (i = 0; i < rt->size; i++) {
+        ret = njs_external_state_init(vm, &rt->states[i], opts);
+        if (ret != NJS_OK) {
+            njs_stderror("njs_external_state_init() failed\n");
+            return NULL;
+        }
+    }
+
+    return rt;
+}
+
+
+static njs_external_state_t *
+njs_runtime_next_state(njs_runtime_t *rt, njs_opts_t *opts)
+{
+    unsigned  next, n;
+
+    n = 0;
+    next = ((opts->async) ? (unsigned) random() : rt->current++) % rt->size;
+
+    while (rt->states[next].state == sw_done) {
+        next++;
+        next = next % rt->size;
+
+        n++;
+
+        if (n == rt->size) {
+            return NULL;
+        }
+    }
+
+    return &rt->states[next];
+}
+
+
+static void
+njs_runtime_destroy(njs_runtime_t *rt)
+{
+    njs_uint_t  i;
+
+    for (i = 0; i < rt->size; i++) {
+        if (rt->states[i].vm != NULL) {
+            njs_vm_destroy(rt->states[i].vm);
+        }
+    }
+}
+
+
+static njs_int_t
+njs_process_test(njs_external_state_t *state, njs_opts_t *opts,
+    njs_unit_test_t *expected)
+{
+    njs_int_t    ret;
+    njs_str_t    s;
+    njs_bool_t   success;
+    njs_value_t  request;
+
+    static const njs_str_t  handler_str = njs_str("main.handler");
+    static const njs_str_t  request_str = njs_str("$r");
+
+    switch (state->state) {
+    case sw_start:
+        state->state = sw_handler;
+
+        ret = njs_vm_start(state->vm);
+        if (ret != NJS_OK) {
+            goto done;
+        }
+
+        if (opts->async) {
+            return NJS_OK;
+        }
+
+        /* Fall through. */
+    case sw_handler:
+        state->state = sw_loop;
+
+        if (opts->handler) {
+            ret = njs_vm_value(state->vm, &request_str, &request);
+            if (ret != NJS_OK) {
+                njs_stderror("njs_vm_value(\"%V\") failed\n", &request_str);
+                return NJS_ERROR;
+            }
+
+            ret = njs_external_call(state->vm, &handler_str, &request, 1);
+            if (ret == NJS_ERROR) {
+                goto done;
+            }
+
+            if (opts->async) {
+                return NJS_OK;
+            }
+        }
+
+        /* Fall through. */
+    case sw_loop:
+    default:
+        for ( ;; ) {
+            if (!njs_vm_pending(state->vm)) {
+                break;
+            }
+
+            ret = njs_external_process_events(state->vm, state->env);
+            if (ret != NJS_OK) {
+                njs_stderror("njs_external_process_events() failed\n");
+                return NJS_ERROR;
+            }
+
+            if (njs_vm_waiting(state->vm) && !njs_vm_posted(state->vm)) {
+                /*TODO: async events. */
+
+                njs_stderror("njs_process_test(): async events unsupported\n");
+                return NJS_ERROR;
+            }
+
+            (void) njs_vm_run(state->vm);
+
+            if (opts->async) {
+                return NJS_OK;
+            }
+        }
+    }
+
+done:
+
+    state->state = sw_done;
+
+    if (njs_external_retval(state, &s) != NJS_OK) {
+        njs_stderror("njs_external_retval() failed\n");
+        return NJS_ERROR;
+    }
+
+    success = njs_strstr_eq(&expected->ret, &s);
+    if (!success) {
+        njs_stderror("njs(\"%V\")\nexpected: \"%V\"\n     got: \"%V\"\n",
+                     &expected->script, &expected->ret, &s);
+
+        return NJS_DECLINED;
+    }
+
+    njs_vm_destroy(state->vm);
+    state->vm = NULL;
+
+    return NJS_OK;
+}
+
+
+static njs_int_t
 njs_unit_test(njs_unit_test_t tests[], size_t num, njs_str_t *name,
     njs_opts_t *opts, njs_stat_t *stat)
 {
-    u_char        *start, *end;
-    njs_vm_t      *vm, *nvm;
-    njs_int_t     ret;
-    njs_str_t     s;
-    njs_uint_t    i, repeat;
-    njs_stat_t    prev;
-    njs_bool_t    success;
-    njs_vm_opt_t  options;
+    u_char                *start, *end;
+    njs_vm_t              *vm;
+    njs_int_t             ret;
+    njs_str_t             s;
+    njs_bool_t            success;
+    njs_uint_t            i;
+    njs_stat_t            prev;
+    njs_vm_opt_t          options;
+    njs_runtime_t         *rt;
+    njs_external_state_t  *state;
 
     vm = NULL;
-    nvm = NULL;
+    rt = NULL;
 
     prev = *stat;
 
@@ -21609,32 +21893,34 @@ njs_unit_test(njs_unit_test_t tests[], s
                 njs_disassembler(vm);
             }
 
-            repeat = opts->repeat;
-
-            do {
-                if (nvm != NULL) {
-                    njs_vm_destroy(nvm);
+            rt = njs_runtime_init(vm, opts);
+            if (rt == NULL) {
+                njs_stderror("njs_runtime_init() failed\n");
+                goto done;
+            }
+
+            for ( ;; ) {
+                state = njs_runtime_next_state(rt, opts);
+                if (state == NULL) {
+                    break;
                 }
 
-                nvm = njs_vm_clone(vm, NULL);
-                if (nvm == NULL) {
-                    njs_printf("njs_vm_clone() failed\n");
+                ret = njs_process_test(state, opts, &tests[i]);
+                if (ret != NJS_OK) {
+                    if (ret == NJS_DECLINED) {
+                        break;
+                    }
+
+                    njs_stderror("njs_process_test() failed\n");
                     goto done;
                 }
-
-                if (opts->externals) {
-                    ret = njs_externals_init(nvm);
-                    if (ret != NJS_OK) {
-                        goto done;
-                    }
-                }
-
-                ret = njs_vm_start(nvm);
-            } while (--repeat != 0);
-
-            if (njs_vm_retval_string(nvm, &s) != NJS_OK) {
-                njs_printf("njs_vm_retval_string() failed\n");
-                goto done;
+            }
+
+            success = (ret == NJS_OK);
+
+            if (rt != NULL) {
+                njs_runtime_destroy(rt);
+                rt = NULL;
             }
 
         } else {
@@ -21648,23 +21934,20 @@ njs_unit_test(njs_unit_test_t tests[], s
                 s = njs_str_value("Error: "
                                   "Extra characters at the end of the script");
             }
-        }
-
-        success = njs_strstr_eq(&tests[i].ret, &s);
-
-        if (!success) {
-            njs_printf("njs(\"%V\")\nexpected: \"%V\"\n     got: \"%V\"\n",
-                       &tests[i].script, &tests[i].ret, &s);
-
-            stat->failed++;
+
+            success = njs_strstr_eq(&tests[i].ret, &s);
+            if (!success) {
+                njs_stderror("njs(\"%V\")\nexpected: \"%V\"\n"
+                             "     got: \"%V\"\n",
+                             &tests[i].script, &tests[i].ret, &s);
+            }
+        }
+
+        if (success) {
+            stat->passed++;
 
         } else {
-            stat->passed++;
-        }
-
-        if (nvm != NULL) {
-            njs_vm_destroy(nvm);
-            nvm = NULL;
+            stat->failed++;
         }
 
         njs_vm_destroy(vm);
@@ -21675,8 +21958,8 @@ njs_unit_test(njs_unit_test_t tests[], s
 
 done:
 
-    if (nvm != NULL) {
-        njs_vm_destroy(nvm);
+    if (rt != NULL) {
+        njs_runtime_destroy(rt);
     }
 
     if (vm != NULL) {
@@ -22784,7 +23067,7 @@ done:
 
 
 static njs_int_t
-njs_get_options(njs_opts_t *opts, int argc, char **argv)
+njs_options_parse(njs_opts_t *opts, int argc, char **argv)
 {
     char       *p;
     njs_int_t  i;
@@ -22798,6 +23081,7 @@ njs_get_options(njs_opts_t *opts, int ar
         "  -d                           print disassembled code.\n"
         "  -f PATTERN1[|PATTERN2..]     filter test suites to run.\n"
         "  -r count                     overrides repeat count for tests.\n"
+        "  -s seed                      sets seed for async tests.\n"
         "  -v                           verbose mode.\n";
 
     for (i = 1; i < argc; i++) {
@@ -22839,6 +23123,15 @@ njs_get_options(njs_opts_t *opts, int ar
             njs_stderror("option \"-r\" requires argument\n");
             return NJS_ERROR;
 
+        case 's':
+            if (++i < argc) {
+                opts->seed = atoi(argv[i]);
+                break;
+            }
+
+            njs_stderror("option \"-s\" requires argument\n");
+            return NJS_ERROR;
+
         case 'v':
             opts->verbose = 1;
             break;
@@ -22967,8 +23260,14 @@ static njs_test_suite_t  njs_suites[] =
       njs_nitems(njs_externals_test),
       njs_unit_test },
 
+    { njs_str("async handler"),
+      { .async = 1, .externals = 1, .handler = 1, .repeat = 4, .seed = 2, .unsafe = 1 },
+      njs_async_handler_test,
+      njs_nitems(njs_async_handler_test),
+      njs_unit_test },
+
     { njs_str("shared"),
-      { .externals = 1, .repeat = 128, .unsafe = 1, .backtrace = 1 },
+      { .externals = 1, .repeat = 128, .seed = 42, .unsafe = 1, .backtrace = 1 },
       njs_shared_test,
       njs_nitems(njs_shared_test),
       njs_unit_test },
@@ -23022,7 +23321,7 @@ main(int argc, char **argv)
 
     njs_memzero(&opts, sizeof(njs_opts_t));
 
-    ret = njs_get_options(&opts, argc, argv);
+    ret = njs_options_parse(&opts, argc, argv);
     if (ret != NJS_OK) {
         return (ret == NJS_DONE) ? EXIT_SUCCESS: EXIT_FAILURE;
     }
@@ -23045,6 +23344,7 @@ main(int argc, char **argv)
 
         op.disassemble = opts.disassemble;
         op.repeat = opts.repeat ? opts.repeat : op.repeat;
+        op.seed = opts.seed ? opts.seed : op.seed;
         op.verbose = opts.verbose;
 
         ret = suite->run(suite->tests, suite->n, &suite->name, &op, &stat);


More information about the nginx-devel mailing list