From cdc7e4479ff5aa08df0857a13a7acd7a00b79c89 Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Wed, 30 Aug 2017 00:31:02 +0300 Subject: Lib unit tests have been renamed to tests. --- auto/make | 27 +- auto/options | 4 +- auto/sources | 42 +-- configure | 1 - src/nxt_main.h | 7 - src/nxt_random.c | 9 +- src/nxt_random.h | 4 +- test/nxt_gmtime_test.c | 84 +++++ test/nxt_gmtime_unit_test.c | 83 ----- test/nxt_http_parse_test.c | 714 +++++++++++++++++++++++++++++++++++++++ test/nxt_http_parse_unit_test.c | 716 ---------------------------------------- test/nxt_lib_unit_test.c | 161 --------- test/nxt_lib_unit_test.h | 71 ---- test/nxt_lvlhsh_test.c | 229 +++++++++++++ test/nxt_lvlhsh_unit_test.c | 228 ------------- test/nxt_malloc_test.c | 123 +++++++ test/nxt_malloc_unit_test.c | 122 ------- test/nxt_mem_zone_test.c | 74 +++++ test/nxt_mem_zone_unit_test.c | 73 ---- test/nxt_mp_test.c | 90 +++++ test/nxt_mp_unit_test.c | 89 ----- test/nxt_msec_diff_test.c | 46 +++ test/nxt_msec_diff_unit_test.c | 45 --- test/nxt_rbtree1_test.c | 343 +++++++++++++++++++ test/nxt_rbtree1_unit_test.c | 345 ------------------- test/nxt_rbtree_test.c | 279 ++++++++++++++++ test/nxt_rbtree_unit_test.c | 279 ---------------- test/nxt_sprintf_test.c | 71 ++++ test/nxt_sprintf_unit_test.c | 70 ---- test/nxt_term_parse_test.c | 60 ++++ test/nxt_term_parse_unit_test.c | 59 ---- test/nxt_tests.c | 162 +++++++++ test/nxt_tests.h | 68 ++++ test/nxt_utf8_file_name_test.c | 2 +- test/nxt_utf8_test.c | 191 +++++++++++ test/nxt_utf8_unit_test.c | 190 ----------- 36 files changed, 2575 insertions(+), 2586 deletions(-) create mode 100644 test/nxt_gmtime_test.c delete mode 100644 test/nxt_gmtime_unit_test.c create mode 100644 test/nxt_http_parse_test.c delete mode 100644 test/nxt_http_parse_unit_test.c delete mode 100644 test/nxt_lib_unit_test.c delete mode 100644 test/nxt_lib_unit_test.h create mode 100644 test/nxt_lvlhsh_test.c delete mode 100644 test/nxt_lvlhsh_unit_test.c create mode 100644 test/nxt_malloc_test.c delete mode 100644 test/nxt_malloc_unit_test.c create mode 100644 test/nxt_mem_zone_test.c delete mode 100644 test/nxt_mem_zone_unit_test.c create mode 100644 test/nxt_mp_test.c delete mode 100644 test/nxt_mp_unit_test.c create mode 100644 test/nxt_msec_diff_test.c delete mode 100644 test/nxt_msec_diff_unit_test.c create mode 100644 test/nxt_rbtree1_test.c delete mode 100644 test/nxt_rbtree1_unit_test.c create mode 100644 test/nxt_rbtree_test.c delete mode 100644 test/nxt_rbtree_unit_test.c create mode 100644 test/nxt_sprintf_test.c delete mode 100644 test/nxt_sprintf_unit_test.c create mode 100644 test/nxt_term_parse_test.c delete mode 100644 test/nxt_term_parse_unit_test.c create mode 100644 test/nxt_tests.c create mode 100644 test/nxt_tests.h create mode 100644 test/nxt_utf8_test.c delete mode 100644 test/nxt_utf8_unit_test.c diff --git a/auto/make b/auto/make index f0733f3f..e977210f 100644 --- a/auto/make +++ b/auto/make @@ -45,7 +45,7 @@ $echo >> $NXT_MAKEFILE $echo "NXT_LIB_DEPS = \\" >> $NXT_MAKEFILE -for nxt_dep in $NXT_LIB_DEPS $NXT_LIB_UNIT_TEST_DEPS $NXT_AUTO_CONFIG_H +for nxt_dep in $NXT_LIB_DEPS $NXT_TEST_DEPS $NXT_AUTO_CONFIG_H do $echo " $nxt_dep \\" >> $NXT_MAKEFILE done @@ -87,7 +87,7 @@ END # Object files. -for nxt_src in $NXT_LIB_SRCS $NXT_LIB_UNIT_TEST_SRCS +for nxt_src in $NXT_LIB_SRCS $NXT_TEST_SRCS do nxt_obj=`$echo $nxt_src | sed -e "s/\.c$/\.o/"` cat << END >> $NXT_MAKEFILE @@ -103,25 +103,25 @@ done $echo >> $NXT_MAKEFILE -# Unit test object files list. +# Test object files list. -$echo "NXT_LIB_UNIT_TEST_OBJS = \\" >> $NXT_MAKEFILE +$echo "NXT_TEST_OBJS = \\" >> $NXT_MAKEFILE -for nxt_src in $NXT_LIB_UNIT_TEST_SRCS +for nxt_src in $NXT_TEST_SRCS do nxt_obj=`$echo $nxt_src | sed -e "s/\.c$/\.o/"` $echo " $NXT_BUILD_DIR/$nxt_obj \\" >> $NXT_MAKEFILE done -# Unit test and utf8 test executables. +# Test executables. cat << END >> $NXT_MAKEFILE -$NXT_BUILD_DIR/lib_unit_test: \$(NXT_LIB_UNIT_TEST_OBJS) \\ +$NXT_BUILD_DIR/tests: \$(NXT_TEST_OBJS) \\ $NXT_BUILD_DIR/$NXT_LIB_STATIC \$(NXT_LIB_DEPS) - \$(NXT_EXEC_LINK) -o $NXT_BUILD_DIR/lib_unit_test \\ - \$(CFLAGS) \$(NXT_LIB_UNIT_TEST_OBJS) \\ + \$(NXT_EXEC_LINK) -o $NXT_BUILD_DIR/tests \\ + \$(CFLAGS) \$(NXT_TEST_OBJS) \\ $NXT_BUILD_DIR/$NXT_LIB_STATIC \\ $NXT_LD_OPT $NXT_LIBM $NXT_LIBS $NXT_LIB_AUX_LIBS @@ -136,11 +136,6 @@ $NXT_BUILD_DIR/utf8_file_name_test: $NXT_LIB_UTF8_FILE_NAME_TEST_SRCS \\ END -if [ $NXT_LIB_UNIT_TEST = YES ]; then - NXT_UNIT_TEST_TARGETS="$NXT_UNIT_TEST_TARGETS lib_test" -fi - - NXT_MAKE_INCS="src $NXT_BUILD_DIR" NXT_MAKE_DEPS="\$(NXT_LIB_DEPS) $NXT_DEPS" NXT_MAKE_SRCS="$NXT_SRCS" @@ -222,8 +217,8 @@ cat << END > Makefile include $NXT_MAKEFILE -.PHONY: lib_test -lib_test: $NXT_BUILD_DIR/lib_unit_test $NXT_BUILD_DIR/utf8_file_name_test +.PHONY: tests +tests: $NXT_BUILD_DIR/tests $NXT_BUILD_DIR/utf8_file_name_test clean: rm -rf $NXT_BUILD_DIR *.dSYM Makefile diff --git a/auto/options b/auto/options index 67f53258..19cd3dee 100644 --- a/auto/options +++ b/auto/options @@ -38,7 +38,7 @@ NXT_TEST_BUILD_SOLARIS_SENDFILEV=NO NXT_TEST_BUILD_AIX_SEND_FILE=NO NXT_TEST_BUILD_HPUX_SENDFILE=NO -NXT_LIB_UNIT_TEST=NO +NXT_TESTS=NO for nxt_option do @@ -89,7 +89,7 @@ do --test-build-aix-send_file) NXT_TEST_BUILD_AIX_SEND_FILE=YES ;; --test-build-hpux-sendfile) NXT_TEST_BUILD_HPUX_SENDFILE=YES ;; - --tests) NXT_LIB_UNIT_TEST=YES ;; + --tests) NXT_TESTS=YES ;; *) $echo diff --git a/auto/sources b/auto/sources index eab4e29b..c1d8b37f 100644 --- a/auto/sources +++ b/auto/sources @@ -198,28 +198,28 @@ NXT_LIB_MACOSX_SENDFILE_SRCS="src/nxt_macosx_sendfile.c" NXT_LIB_AIX_SEND_FILE_SRCS="src/nxt_aix_send_file.c" NXT_LIB_HPUX_SENDFILE_SRCS="src/nxt_hpux_sendfile.c" -NXT_LIB_TEST_BUILD_DEPS="src/nxt_test_build.h" -NXT_LIB_TEST_BUILD_SRCS="src/nxt_test_build.c" +NXT_TEST_BUILD_DEPS="src/nxt_test_build.h" +NXT_TEST_BUILD_SRCS="src/nxt_test_build.c" -NXT_LIB_UNIT_TEST_DEPS="test/nxt_lib_unit_test.h \ +NXT_TEST_DEPS="test/nxt_tests.h \ test/nxt_rbtree1.h \ " -NXT_LIB_UNIT_TEST_SRCS=" \ - test/nxt_lib_unit_test.c \ +NXT_TEST_SRCS=" \ + test/nxt_tests.c \ test/nxt_rbtree1.c \ - test/nxt_rbtree_unit_test.c \ - test/nxt_term_parse_unit_test.c \ - test/nxt_msec_diff_unit_test.c \ - test/nxt_mp_unit_test.c \ - test/nxt_mem_zone_unit_test.c \ - test/nxt_lvlhsh_unit_test.c \ - test/nxt_gmtime_unit_test.c \ - test/nxt_sprintf_unit_test.c \ - test/nxt_malloc_unit_test.c \ - test/nxt_utf8_unit_test.c \ - test/nxt_rbtree1_unit_test.c \ - test/nxt_http_parse_unit_test.c \ + test/nxt_rbtree_test.c \ + test/nxt_term_parse_test.c \ + test/nxt_msec_diff_test.c \ + test/nxt_mp_test.c \ + test/nxt_mem_zone_test.c \ + test/nxt_lvlhsh_test.c \ + test/nxt_gmtime_test.c \ + test/nxt_sprintf_test.c \ + test/nxt_malloc_test.c \ + test/nxt_utf8_test.c \ + test/nxt_rbtree1_test.c \ + test/nxt_http_parse_test.c \ " NXT_LIB_UTF8_FILE_NAME_TEST_SRCS=" \ @@ -323,13 +323,13 @@ fi if [ "$NXT_TEST_BUILD" = "YES" ]; then - NXT_LIB_DEPS="$NXT_LIB_DEPS $NXT_LIB_TEST_BUILD_DEPS" - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_TEST_BUILD_SRCS" + NXT_LIB_DEPS="$NXT_LIB_DEPS $NXT_TEST_BUILD_DEPS" + NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_TEST_BUILD_SRCS" fi -if [ $NXT_LIB_UNIT_TEST = YES ]; then - nxt_have=NXT_LIB_UNIT_TEST . auto/have +if [ $NXT_TESTS = YES ]; then + nxt_have=NXT_TESTS . auto/have fi NXT_DEPS=" \ diff --git a/configure b/configure index f9f6eb8b..b845df54 100755 --- a/configure +++ b/configure @@ -18,7 +18,6 @@ set -u CFLAGS=${CFLAGS=} NXT_TEST_CFLAGS=${NXT_TEST_CFLAGS=} NXT_TEST_LIBS=${NXT_TEST_LIBS=} -NXT_UNIT_TEST_TARGETS=${NXT_UNIT_TEST_TARGETS=} # STUB NXT_BUILD_DIR=build diff --git a/src/nxt_main.h b/src/nxt_main.h index a0be58a1..c7776c8b 100644 --- a/src/nxt_main.h +++ b/src/nxt_main.h @@ -161,13 +161,6 @@ typedef struct nxt_upstream_source_s nxt_upstream_source_t; #include -#if (NXT_LIB_UNIT_TEST) -#include <../test/nxt_lib_unit_test.h> -#else -#define NXT_LIB_UNIT_TEST_STATIC static -#endif - - /* * The envp argument must be &environ if application may * change its process title with nxt_process_title(). diff --git a/src/nxt_random.c b/src/nxt_random.c index ea73ae18..38b14e56 100644 --- a/src/nxt_random.c +++ b/src/nxt_random.c @@ -162,10 +162,10 @@ nxt_random_byte(nxt_random_t *r) } -#if (NXT_LIB_UNIT_TEST) +#if (NXT_TESTS) nxt_int_t -nxt_random_unit_test(nxt_thread_t *thr) +nxt_random_test(nxt_thread_t *thr) { nxt_uint_t n; nxt_random_t r; @@ -188,14 +188,13 @@ nxt_random_unit_test(nxt_thread_t *thr) } if (nxt_random(&r) == 0x6FCAE186) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "arc4random unit test passed"); + nxt_log_error(NXT_LOG_NOTICE, thr->log, "arc4random test passed"); return NXT_OK; } } - nxt_log_error(NXT_LOG_NOTICE, thr->log, "arc4random unit test failed"); + nxt_log_error(NXT_LOG_NOTICE, thr->log, "arc4random test failed"); return NXT_ERROR; } diff --git a/src/nxt_random.h b/src/nxt_random.h index f9c07e54..962fdf8f 100644 --- a/src/nxt_random.h +++ b/src/nxt_random.h @@ -19,8 +19,8 @@ typedef struct { void nxt_random_init(nxt_random_t *r); uint32_t nxt_random(nxt_random_t *r); -#if (NXT_LIB_UNIT_TEST) -nxt_int_t nxt_random_unit_test(nxt_thread_t *thr); +#if (NXT_TESTS) +nxt_int_t nxt_random_test(nxt_thread_t *thr); #endif diff --git a/test/nxt_gmtime_test.c b/test/nxt_gmtime_test.c new file mode 100644 index 00000000..cec81ab4 --- /dev/null +++ b/test/nxt_gmtime_test.c @@ -0,0 +1,84 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include "nxt_tests.h" + + +#if (NXT_TIME_T_SIZE == 4) + +/* A 86400-fold number below 2^31. */ +#define NXT_GMTIME_MAX 2147472000 + +#else +/* + * March 19, 29398 is maximum valid data if nxt_uint_t + * is 4 bytes size whilst nxt_time_t is 8 bytes size. + */ +#define NXT_GMTIME_MAX 865550793600 +#endif + + +nxt_int_t +nxt_gmtime_test(nxt_thread_t *thr) +{ + struct tm tm0, *tm1; + nxt_time_t s; + nxt_nsec_t start, end; + + nxt_thread_time_update(thr); + nxt_log_error(NXT_LOG_NOTICE, thr->log, "gmtime test started"); + + for (s = 0; s < NXT_GMTIME_MAX; s += 86400) { + + nxt_gmtime(s, &tm0); + tm1 = gmtime(&s); + + if (tm0.tm_mday != tm1->tm_mday + || tm0.tm_mon != tm1->tm_mon + || tm0.tm_year != tm1->tm_year + || tm0.tm_yday != tm1->tm_yday + || tm0.tm_wday != tm1->tm_wday) + { + nxt_log_alert(thr->log, + "gmtime test failed: %T @ %02d.%02d.%d", + s, tm1->tm_mday, tm1->tm_mon + 1, + tm1->tm_year + 1900); + return NXT_ERROR; + } + } + + + nxt_thread_time_update(thr); + start = nxt_thread_monotonic_time(thr); + + for (s = 0; s < 10000000; s++) { + nxt_gmtime(s, &tm0); + } + + nxt_thread_time_update(thr); + end = nxt_thread_monotonic_time(thr); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "nxt_gmtime(): %0.1fns", + (end - start) / 10000000.0); + + + nxt_thread_time_update(thr); + start = nxt_thread_monotonic_time(thr); + + for (s = 0; s < 10000000; s++) { + (void) gmtime(&s); + } + + nxt_thread_time_update(thr); + end = nxt_thread_monotonic_time(thr); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "gmtime(): %0.1fns", + (end - start) / 10000000.0); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "gmtime test passed"); + return NXT_OK; +} diff --git a/test/nxt_gmtime_unit_test.c b/test/nxt_gmtime_unit_test.c deleted file mode 100644 index eea916f3..00000000 --- a/test/nxt_gmtime_unit_test.c +++ /dev/null @@ -1,83 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -#if (NXT_TIME_T_SIZE == 4) - -/* A 86400-fold number below 2^31. */ -#define NXT_GMTIME_MAX 2147472000 - -#else -/* - * March 19, 29398 is maximum valid data if nxt_uint_t - * is 4 bytes size whilst nxt_time_t is 8 bytes size. - */ -#define NXT_GMTIME_MAX 865550793600 -#endif - - -nxt_int_t -nxt_gmtime_unit_test(nxt_thread_t *thr) -{ - struct tm tm0, *tm1; - nxt_time_t s; - nxt_nsec_t start, end; - - nxt_thread_time_update(thr); - nxt_log_error(NXT_LOG_NOTICE, thr->log, "gmtime unit test started"); - - for (s = 0; s < NXT_GMTIME_MAX; s += 86400) { - - nxt_gmtime(s, &tm0); - tm1 = gmtime(&s); - - if (tm0.tm_mday != tm1->tm_mday - || tm0.tm_mon != tm1->tm_mon - || tm0.tm_year != tm1->tm_year - || tm0.tm_yday != tm1->tm_yday - || tm0.tm_wday != tm1->tm_wday) - { - nxt_log_alert(thr->log, - "gmtime unit test failed: %T @ %02d.%02d.%d", - s, tm1->tm_mday, tm1->tm_mon + 1, - tm1->tm_year + 1900); - return NXT_ERROR; - } - } - - - nxt_thread_time_update(thr); - start = nxt_thread_monotonic_time(thr); - - for (s = 0; s < 10000000; s++) { - nxt_gmtime(s, &tm0); - } - - nxt_thread_time_update(thr); - end = nxt_thread_monotonic_time(thr); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "nxt_gmtime(): %0.1fns", - (end - start) / 10000000.0); - - - nxt_thread_time_update(thr); - start = nxt_thread_monotonic_time(thr); - - for (s = 0; s < 10000000; s++) { - (void) gmtime(&s); - } - - nxt_thread_time_update(thr); - end = nxt_thread_monotonic_time(thr); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "gmtime(): %0.1fns", - (end - start) / 10000000.0); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "gmtime unit test passed"); - return NXT_OK; -} diff --git a/test/nxt_http_parse_test.c b/test/nxt_http_parse_test.c new file mode 100644 index 00000000..d2af4245 --- /dev/null +++ b/test/nxt_http_parse_test.c @@ -0,0 +1,714 @@ + +/* + * Copyright (C) NGINX, Inc. + * Copyright (C) Valentin V. Bartenev + */ + +#include +#include "nxt_tests.h" + + +typedef struct { + nxt_str_t method; + nxt_str_t target; + nxt_str_t exten; + nxt_str_t args; + u_char version[8]; + + /* target with "/." */ + unsigned complex_target:1; + /* target with "%" */ + unsigned quoted_target:1; + /* target with " " */ + unsigned space_in_target:1; + /* target with "+" */ + unsigned plus_in_target:1; +} nxt_http_parse_test_request_line_t; + + +typedef union { + void *pointer; + nxt_int_t result; + nxt_http_parse_test_request_line_t request_line; +} nxt_http_parse_test_data_t; + + +typedef struct { + nxt_str_t request; + nxt_int_t result; + nxt_int_t (*handler)(nxt_http_request_parse_t *rp, + nxt_http_parse_test_data_t *data, + nxt_str_t *request, nxt_log_t *log); + + nxt_http_parse_test_data_t data; +} nxt_http_parse_test_case_t; + + +static nxt_int_t nxt_http_parse_test_run(nxt_http_request_parse_t *rp, + nxt_str_t *request); +static nxt_int_t nxt_http_parse_test_bench(nxt_thread_t *thr, + nxt_str_t *request, nxt_http_fields_hash_t *hash, const char *name, + nxt_uint_t n); +static nxt_int_t nxt_http_parse_test_request_line(nxt_http_request_parse_t *rp, + nxt_http_parse_test_data_t *data, + nxt_str_t *request, nxt_log_t *log); +static nxt_int_t nxt_http_parse_test_fields(nxt_http_request_parse_t *rp, + nxt_http_parse_test_data_t *data, nxt_str_t *request, nxt_log_t *log); + + +static nxt_int_t nxt_http_test_header_return(void *ctx, nxt_http_field_t *field, + nxt_log_t *log); + + +static nxt_http_parse_test_case_t nxt_http_test_cases[] = { + { + nxt_string("GET / HTTP/1.0\r\n\r\n"), + NXT_DONE, + &nxt_http_parse_test_request_line, + { .request_line = { + nxt_string("GET"), + nxt_string("/"), + nxt_null_string, + nxt_null_string, + "HTTP/1.0", + 0, 0, 0, 0 + }} + }, + { + nxt_string("XXX-METHOD /d.ir/fi+le.ext?key=val HTTP/1.2\n\n"), + NXT_DONE, + &nxt_http_parse_test_request_line, + { .request_line = { + nxt_string("XXX-METHOD"), + nxt_string("/d.ir/fi+le.ext?key=val"), + nxt_string("ext?key=val"), + nxt_string("key=val"), + "HTTP/1.2", + 0, 0, 0, 1 + }} + }, + { + nxt_string("GET /di.r/? HTTP/1.0\r\n\r\n"), + NXT_DONE, + &nxt_http_parse_test_request_line, + { .request_line = { + nxt_string("GET"), + nxt_string("/di.r/?"), + nxt_null_string, + nxt_string(""), + "HTTP/1.0", + 0, 0, 0, 0 + }} + }, + { + nxt_string("GEt / HTTP/1.0\r\n\r\n"), + NXT_ERROR, + NULL, { NULL } + }, + { + nxt_string("GET /\0 HTTP/1.0\r\n\r\n"), + NXT_ERROR, + NULL, { NULL } + }, + { + nxt_string("GET /\r HTTP/1.0\r\n\r\n"), + NXT_ERROR, + NULL, { NULL } + }, + { + nxt_string("GET /\n HTTP/1.0\r\n\r\n"), + NXT_ERROR, + NULL, { NULL } + }, + { + nxt_string("GET / HTTP/1.0\r\r\n"), + NXT_ERROR, + NULL, { NULL } + }, + { + nxt_string("GET /. HTTP/1.0\r\n\r\n"), + NXT_DONE, + &nxt_http_parse_test_request_line, + { .request_line = { + nxt_string("GET"), + nxt_string("/."), + nxt_null_string, + nxt_null_string, + "HTTP/1.0", + 1, 0, 0, 0 + }} + }, + { + nxt_string("GET /# HTTP/1.0\r\n\r\n"), + NXT_DONE, + &nxt_http_parse_test_request_line, + { .request_line = { + nxt_string("GET"), + nxt_string("/#"), + nxt_null_string, + nxt_null_string, + "HTTP/1.0", + 1, 0, 0, 0 + }} + }, + { + nxt_string("GET /?# HTTP/1.0\r\n\r\n"), + NXT_DONE, + &nxt_http_parse_test_request_line, + { .request_line = { + nxt_string("GET"), + nxt_string("/?#"), + nxt_null_string, + nxt_string("#"), + "HTTP/1.0", + 1, 0, 0, 0 + }} + }, + { + nxt_string("GET // HTTP/1.0\r\n\r\n"), + NXT_DONE, + &nxt_http_parse_test_request_line, + { .request_line = { + nxt_string("GET"), + nxt_string("//"), + nxt_null_string, + nxt_null_string, + "HTTP/1.0", + 1, 0, 0, 0 + }} + }, + { + nxt_string("GET /%20 HTTP/1.0\r\n\r\n"), + NXT_DONE, + &nxt_http_parse_test_request_line, + { .request_line = { + nxt_string("GET"), + nxt_string("/%20"), + nxt_null_string, + nxt_null_string, + "HTTP/1.0", + 0, 1, 0, 0 + }} + }, + { + nxt_string("GET / a HTTP/1.0\r\n\r\n"), + NXT_DONE, + &nxt_http_parse_test_request_line, + { .request_line = { + nxt_string("GET"), + nxt_string("/ a"), + nxt_null_string, + nxt_null_string, + "HTTP/1.0", + 0, 0, 1, 0 + }} + }, + { + nxt_string("GET / HTTP/1.0 HTTP/1.1\r\n\r\n"), + NXT_DONE, + &nxt_http_parse_test_request_line, + { .request_line = { + nxt_string("GET"), + nxt_string("/ HTTP/1.0"), + nxt_null_string, + nxt_null_string, + "HTTP/1.1", + 0, 0, 1, 0 + }} + }, + { + nxt_string("GET / HTTP/1.1\r\n" + "Host: example.com\r\n\r\n"), + NXT_DONE, + NULL, { NULL } + }, + { + nxt_string("GET / HTTP/1.1\r\n" + "Host:\r\n\r\n"), + NXT_DONE, + NULL, { NULL } + }, + { + nxt_string("GET / HTTP/1.1\r\n" + "Host example.com\r\n\r\n"), + NXT_ERROR, + NULL, { NULL } + }, + { + nxt_string("GET / HTTP/1.1\r\n" + ":Host: example.com\r\n\r\n"), + NXT_ERROR, + NULL, { NULL } + }, + { + nxt_string("GET / HTTP/1.1\r\n" + "Ho_st: example.com\r\n\r\n"), + NXT_ERROR, + NULL, { NULL } + }, + { + nxt_string("GET / HTTP/1.1\r\n" + "Ho\0st: example.com\r\n\r\n"), + NXT_ERROR, + NULL, { NULL } + }, + { + nxt_string("GET / HTTP/1.1\r\n" + "Ho\rst: example.com\r\n\r\n"), + NXT_ERROR, + NULL, { NULL } + }, + { + nxt_string("GET / HTTP/1.1\r\n" + "Host: exa\0mple.com\r\n\r\n"), + NXT_ERROR, + NULL, { NULL } + }, + { + nxt_string("GET / HTTP/1.1\r\n" + "Host: exa\rmple.com\r\n\r\n"), + NXT_ERROR, + NULL, { NULL } + }, + { + nxt_string("GET / HTTP/1.1\r\n" + "X-Unknown-Header: value\r\n" + "X-Good-Header: value\r\n\r\n"), + NXT_DONE, + &nxt_http_parse_test_fields, + { .result = NXT_OK } + }, + { + nxt_string("GET / HTTP/1.1\r\n" + "X-Good-Header: value\r\n" + "X-Unknown-Header: value\r\n" + "X-Bad-Header: value\r\n\r\n"), + NXT_DONE, + &nxt_http_parse_test_fields, + { .result = NXT_ERROR } + }, +}; + + +static nxt_http_fields_hash_entry_t nxt_http_test_fields[] = { + { nxt_string("X-Bad-Header"), + &nxt_http_test_header_return, + (uintptr_t) NXT_ERROR }, + + { nxt_string("X-Good-Header"), + &nxt_http_test_header_return, + (uintptr_t) NXT_OK }, + + { nxt_null_string, NULL, 0 } +}; + + +static nxt_http_fields_hash_entry_t nxt_http_test_bench_fields[] = { + { nxt_string("Host"), + &nxt_http_test_header_return, NXT_OK }, + { nxt_string("User-Agent"), + &nxt_http_test_header_return, NXT_OK }, + { nxt_string("Accept-Encoding"), + &nxt_http_test_header_return, NXT_OK }, + { nxt_string("Accept-Language"), + &nxt_http_test_header_return, NXT_OK }, + { nxt_string("Connection"), + &nxt_http_test_header_return, NXT_OK }, + { nxt_string("Content-Length"), + &nxt_http_test_header_return, NXT_OK }, + { nxt_string("Content-Type"), + &nxt_http_test_header_return, NXT_OK }, + { nxt_string("If-Modified-Since"), + &nxt_http_test_header_return, NXT_OK }, + { nxt_string("If-Match"), + &nxt_http_test_header_return, NXT_OK }, + { nxt_string("Date"), + &nxt_http_test_header_return, NXT_OK }, + { nxt_string("Upgrade"), + &nxt_http_test_header_return, NXT_OK }, + { nxt_string("X-Forwarded-For"), + &nxt_http_test_header_return, NXT_OK }, + { nxt_string("X-Request-ID"), + &nxt_http_test_header_return, NXT_OK }, + + { nxt_null_string, NULL, 0 } +}; + + +static nxt_str_t nxt_http_test_simple_request = nxt_string( + "GET /page HTTP/1.1\r\n" + "Host: example.com\r\n\r\n" +); + + +static nxt_str_t nxt_http_test_big_request = nxt_string( + "POST /path/to/very/interesting/article/on.this.site?arg1=value&arg2=value" + "2&very_big_arg=even_bigger_value HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "User-Agent: Mozilla/5.0 (X11; Gentoo Linux x86_64; rv:42.0) Firefox/42.0" + "\r\n" + "Accept: text/html,application/json,application/xml;q=0.9,*/*;q=0.8\r\n" + "Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4\r\n" + "Accept-Encoding: gzip, deflate, br\r\n" + "If-Modified-Since: Wed, 31 Dec 1986 16:00:00 GMT\r\n" + "Referer: https://example.org/path/to/not-interesting/article.html\r\n" + "Cookie: name=value; name2=value2; some_big_cookie=iVBORw0KGgoAAAANSUhEUgA" + "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\r\n" + "Connection: keep-alive\r\n" + "Content-Length: 0\r\n" + "Upgrade-Insecure-Requests: 1\r\n" + "Pragma: no-cache\r\n" + "Cache-Control: no-cache\r\n" + "X-Forwarded-For: 192.0.2.0, 198.51.100.0, 203.0.113.0\r\n" + "\r\n" +); + + +nxt_int_t +nxt_http_parse_test(nxt_thread_t *thr) +{ + nxt_mp_t *mp, *mp_temp; + nxt_int_t rc; + nxt_uint_t i; + nxt_http_fields_hash_t *hash; + nxt_http_request_parse_t rp; + nxt_http_parse_test_case_t *test; + + nxt_thread_time_update(thr); + + mp = nxt_mp_create(1024, 128, 256, 32); + if (mp == NULL) { + return NXT_ERROR; + } + + hash = nxt_http_fields_hash_create(nxt_http_test_fields, mp); + if (hash == NULL) { + return NXT_ERROR; + } + + for (i = 0; i < nxt_nitems(nxt_http_test_cases); i++) { + test = &nxt_http_test_cases[i]; + + nxt_memzero(&rp, sizeof(nxt_http_request_parse_t)); + + mp_temp = nxt_mp_create(1024, 128, 256, 32); + if (mp_temp == NULL) { + return NXT_ERROR; + } + + if (nxt_http_parse_request_init(&rp, mp_temp) != NXT_OK) { + return NXT_ERROR; + } + + rp.fields_hash = hash; + + rc = nxt_http_parse_test_run(&rp, &test->request); + + if (rc != test->result) { + nxt_log_alert(thr->log, "http parse test case failed:\n" + " - request:\n\"%V\"\n" + " - result: %i (expected: %i)", + &test->request, rc, test->result); + return NXT_ERROR; + } + + if (test->handler != NULL + && test->handler(&rp, &test->data, &test->request, thr->log) + != NXT_OK) + { + return NXT_ERROR; + } + + nxt_mp_destroy(mp_temp); + } + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "http parse test passed"); + + hash = nxt_http_fields_hash_create(nxt_http_test_bench_fields, mp); + if (hash == NULL) { + return NXT_ERROR; + } + + if (nxt_http_parse_test_bench(thr, &nxt_http_test_simple_request, + hash, "simple", 10000000) + != NXT_OK) + { + return NXT_ERROR; + } + + if (nxt_http_parse_test_bench(thr, &nxt_http_test_big_request, + hash, "big", 100000) + != NXT_OK) + { + return NXT_ERROR; + } + + nxt_mp_destroy(mp); + + return NXT_OK; +} + + +static nxt_int_t +nxt_http_parse_test_run(nxt_http_request_parse_t *rp, nxt_str_t *request) +{ + nxt_int_t rc; + nxt_buf_mem_t buf; + + buf.start = request->start; + buf.end = request->start + request->length; + + buf.pos = buf.start; + buf.free = buf.pos + 1; + + do { + buf.free++; + rc = nxt_http_parse_request(rp, &buf); + } while (buf.free < buf.end && rc == NXT_AGAIN); + + return rc; +} + + +static nxt_int_t +nxt_http_parse_test_bench(nxt_thread_t *thr, nxt_str_t *request, + nxt_http_fields_hash_t *hash, const char *name, nxt_uint_t n) +{ + nxt_mp_t *mp; + nxt_nsec_t start, end; + nxt_uint_t i; + nxt_buf_mem_t buf; + nxt_http_request_parse_t rp; + + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "http parse %s request bench started: %uz bytes, %ui runs", + name, request->length, n); + + buf.start = request->start; + buf.end = request->start + request->length; + + nxt_thread_time_update(thr); + start = nxt_thread_monotonic_time(thr); + + for (i = 0; nxt_fast_path(i < n); i++) { + nxt_memzero(&rp, sizeof(nxt_http_request_parse_t)); + + mp = nxt_mp_create(1024, 128, 256, 32); + if (nxt_slow_path(mp == NULL)) { + return NXT_ERROR; + } + + if (nxt_slow_path(nxt_http_parse_request_init(&rp, mp) != NXT_OK)) { + return NXT_ERROR; + } + + rp.fields_hash = hash; + + buf.pos = buf.start; + buf.free = buf.end; + + if (nxt_slow_path(nxt_http_parse_request(&rp, &buf) != NXT_DONE)) { + nxt_log_alert(thr->log, "http parse %s request bench failed " + "while parsing", name); + return NXT_ERROR; + } + + if (nxt_slow_path(nxt_http_fields_process(rp.fields, NULL, thr->log) + != NXT_OK)) + { + nxt_log_alert(thr->log, "http parse %s request bench failed " + "while fields processing", name); + return NXT_ERROR; + } + + nxt_mp_destroy(mp); + } + + nxt_thread_time_update(thr); + end = nxt_thread_monotonic_time(thr); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "http parse %s request bench: %0.3fs", + name, (end - start) / 1000000000.0); + + return NXT_OK; +} + + +static nxt_int_t +nxt_http_parse_test_request_line(nxt_http_request_parse_t *rp, + nxt_http_parse_test_data_t *data, nxt_str_t *request, nxt_log_t *log) +{ + nxt_str_t str; + + nxt_http_parse_test_request_line_t *test = &data->request_line; + + if (rp->method.start != test->method.start + && !nxt_strstr_eq(&rp->method, &test->method)) + { + nxt_log_alert(log, "http parse test case failed:\n" + " - request:\n\"%V\"\n" + " - method: \"%V\" (expected: \"%V\")", + request, &rp->method, &test->method); + return NXT_ERROR; + } + + str.length = rp->target_end - rp->target_start; + str.start = rp->target_start; + + if (str.start != test->target.start + && !nxt_strstr_eq(&str, &test->target)) + { + nxt_log_alert(log, "http parse test case failed:\n" + " - request:\n\"%V\"\n" + " - target: \"%V\" (expected: \"%V\")", + request, &str, &test->target); + return NXT_ERROR; + } + + str.length = (rp->exten_start != NULL) ? rp->target_end - rp->exten_start + : 0; + str.start = rp->exten_start; + + if (str.start != test->exten.start + && !nxt_strstr_eq(&str, &test->exten)) + { + nxt_log_alert(log, "http parse test case failed:\n" + " - request:\n\"%V\"\n" + " - exten: \"%V\" (expected: \"%V\")", + request, &str, &test->exten); + return NXT_ERROR; + } + + str.length = (rp->args_start != NULL) ? rp->target_end - rp->args_start + : 0; + str.start = rp->args_start; + + if (str.start != test->args.start + && !nxt_strstr_eq(&str, &test->args)) + { + nxt_log_alert(log, "http parse test case failed:\n" + " - request:\n\"%V\"\n" + " - args: \"%V\" (expected: \"%V\")", + request, &str, &test->args); + return NXT_ERROR; + } + + if (nxt_memcmp(rp->version.str, test->version, 8) != 0) { + nxt_log_alert(log, "http parse test case failed:\n" + " - request:\n\"%V\"\n" + " - version: \"%*s\" (expected: \"%*s\")", + request, 8, rp->version.str, 8, test->version); + return NXT_ERROR; + } + + if (rp->complex_target != test->complex_target) { + nxt_log_alert(log, "http parse test case failed:\n" + " - request:\n\"%V\"\n" + " - complex_target: %d (expected: %d)", + request, rp->complex_target, test->complex_target); + return NXT_ERROR; + } + + if (rp->quoted_target != test->quoted_target) { + nxt_log_alert(log, "http parse test case failed:\n" + " - request:\n\"%V\"\n" + " - quoted_target: %d (expected: %d)", + request, rp->quoted_target, test->quoted_target); + return NXT_ERROR; + } + + if (rp->space_in_target != test->space_in_target) { + nxt_log_alert(log, "http parse test case failed:\n" + " - request:\n\"%V\"\n" + " - space_in_target: %d (expected: %d)", + request, rp->space_in_target, test->space_in_target); + return NXT_ERROR; + } + + if (rp->plus_in_target != test->plus_in_target) { + nxt_log_alert(log, "http parse test case failed:\n" + " - request:\n\"%V\"\n" + " - plus_in_target: %d (expected: %d)", + request, rp->plus_in_target, test->plus_in_target); + return NXT_ERROR; + } + + return NXT_OK; +} + + +static nxt_int_t +nxt_http_parse_test_fields(nxt_http_request_parse_t *rp, + nxt_http_parse_test_data_t *data, nxt_str_t *request, nxt_log_t *log) +{ + nxt_int_t rc; + + rc = nxt_http_fields_process(rp->fields, NULL, log); + + if (rc != data->result) { + nxt_log_alert(log, "http parse test hash failed:\n" + " - request:\n\"%V\"\n" + " - result: %i (expected: %i)", + request, rc, data->result); + return NXT_ERROR; + } + + return NXT_OK; +} + + +static nxt_int_t +nxt_http_test_header_return(void *ctx, nxt_http_field_t *field, nxt_log_t *log) +{ + return (nxt_int_t) field->data; +} diff --git a/test/nxt_http_parse_unit_test.c b/test/nxt_http_parse_unit_test.c deleted file mode 100644 index fe9b6b97..00000000 --- a/test/nxt_http_parse_unit_test.c +++ /dev/null @@ -1,716 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - * Copyright (C) Valentin V. Bartenev - */ - -#include - - -typedef struct { - nxt_str_t method; - nxt_str_t target; - nxt_str_t exten; - nxt_str_t args; - u_char version[8]; - - /* target with "/." */ - unsigned complex_target:1; - /* target with "%" */ - unsigned quoted_target:1; - /* target with " " */ - unsigned space_in_target:1; - /* target with "+" */ - unsigned plus_in_target:1; -} nxt_http_parse_unit_test_request_line_t; - - -typedef union { - void *pointer; - nxt_int_t result; - nxt_http_parse_unit_test_request_line_t request_line; -} nxt_http_parse_unit_test_data_t; - - -typedef struct { - nxt_str_t request; - nxt_int_t result; - nxt_int_t (*handler)(nxt_http_request_parse_t *rp, - nxt_http_parse_unit_test_data_t *data, - nxt_str_t *request, nxt_log_t *log); - - nxt_http_parse_unit_test_data_t data; -} nxt_http_parse_unit_test_case_t; - - -static nxt_int_t nxt_http_parse_unit_test_run(nxt_http_request_parse_t *rp, - nxt_str_t *request); -static nxt_int_t nxt_http_parse_unit_test_bench(nxt_thread_t *thr, - nxt_str_t *request, nxt_http_fields_hash_t *hash, const char *name, - nxt_uint_t n); -static nxt_int_t nxt_http_parse_unit_test_request_line( - nxt_http_request_parse_t *rp, nxt_http_parse_unit_test_data_t *data, - nxt_str_t *request, nxt_log_t *log); -static nxt_int_t nxt_http_parse_unit_test_fields( - nxt_http_request_parse_t *rp, nxt_http_parse_unit_test_data_t *data, - nxt_str_t *request, nxt_log_t *log); - - -static nxt_int_t nxt_http_unit_test_header_return(void *ctx, - nxt_http_field_t *field, nxt_log_t *log); - - -static nxt_http_parse_unit_test_case_t nxt_http_unit_test_cases[] = { - { - nxt_string("GET / HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_unit_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/"), - nxt_null_string, - nxt_null_string, - "HTTP/1.0", - 0, 0, 0, 0 - }} - }, - { - nxt_string("XXX-METHOD /d.ir/fi+le.ext?key=val HTTP/1.2\n\n"), - NXT_DONE, - &nxt_http_parse_unit_test_request_line, - { .request_line = { - nxt_string("XXX-METHOD"), - nxt_string("/d.ir/fi+le.ext?key=val"), - nxt_string("ext?key=val"), - nxt_string("key=val"), - "HTTP/1.2", - 0, 0, 0, 1 - }} - }, - { - nxt_string("GET /di.r/? HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_unit_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/di.r/?"), - nxt_null_string, - nxt_string(""), - "HTTP/1.0", - 0, 0, 0, 0 - }} - }, - { - nxt_string("GEt / HTTP/1.0\r\n\r\n"), - NXT_ERROR, - NULL, { NULL } - }, - { - nxt_string("GET /\0 HTTP/1.0\r\n\r\n"), - NXT_ERROR, - NULL, { NULL } - }, - { - nxt_string("GET /\r HTTP/1.0\r\n\r\n"), - NXT_ERROR, - NULL, { NULL } - }, - { - nxt_string("GET /\n HTTP/1.0\r\n\r\n"), - NXT_ERROR, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.0\r\r\n"), - NXT_ERROR, - NULL, { NULL } - }, - { - nxt_string("GET /. HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_unit_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/."), - nxt_null_string, - nxt_null_string, - "HTTP/1.0", - 1, 0, 0, 0 - }} - }, - { - nxt_string("GET /# HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_unit_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/#"), - nxt_null_string, - nxt_null_string, - "HTTP/1.0", - 1, 0, 0, 0 - }} - }, - { - nxt_string("GET /?# HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_unit_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/?#"), - nxt_null_string, - nxt_string("#"), - "HTTP/1.0", - 1, 0, 0, 0 - }} - }, - { - nxt_string("GET // HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_unit_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("//"), - nxt_null_string, - nxt_null_string, - "HTTP/1.0", - 1, 0, 0, 0 - }} - }, - { - nxt_string("GET /%20 HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_unit_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/%20"), - nxt_null_string, - nxt_null_string, - "HTTP/1.0", - 0, 1, 0, 0 - }} - }, - { - nxt_string("GET / a HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_unit_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/ a"), - nxt_null_string, - nxt_null_string, - "HTTP/1.0", - 0, 0, 1, 0 - }} - }, - { - nxt_string("GET / HTTP/1.0 HTTP/1.1\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_unit_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/ HTTP/1.0"), - nxt_null_string, - nxt_null_string, - "HTTP/1.1", - 0, 0, 1, 0 - }} - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host: example.com\r\n\r\n"), - NXT_DONE, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host:\r\n\r\n"), - NXT_DONE, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host example.com\r\n\r\n"), - NXT_ERROR, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - ":Host: example.com\r\n\r\n"), - NXT_ERROR, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Ho_st: example.com\r\n\r\n"), - NXT_ERROR, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Ho\0st: example.com\r\n\r\n"), - NXT_ERROR, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Ho\rst: example.com\r\n\r\n"), - NXT_ERROR, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host: exa\0mple.com\r\n\r\n"), - NXT_ERROR, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host: exa\rmple.com\r\n\r\n"), - NXT_ERROR, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "X-Unknown-Header: value\r\n" - "X-Good-Header: value\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_unit_test_fields, - { .result = NXT_OK } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "X-Good-Header: value\r\n" - "X-Unknown-Header: value\r\n" - "X-Bad-Header: value\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_unit_test_fields, - { .result = NXT_ERROR } - }, -}; - - -static nxt_http_fields_hash_entry_t nxt_http_unit_test_fields[] = { - { nxt_string("X-Bad-Header"), - &nxt_http_unit_test_header_return, - (uintptr_t) NXT_ERROR }, - - { nxt_string("X-Good-Header"), - &nxt_http_unit_test_header_return, - (uintptr_t) NXT_OK }, - - { nxt_null_string, NULL, 0 } -}; - - -static nxt_http_fields_hash_entry_t nxt_http_unit_test_bench_fields[] = { - { nxt_string("Host"), - &nxt_http_unit_test_header_return, NXT_OK }, - { nxt_string("User-Agent"), - &nxt_http_unit_test_header_return, NXT_OK }, - { nxt_string("Accept-Encoding"), - &nxt_http_unit_test_header_return, NXT_OK }, - { nxt_string("Accept-Language"), - &nxt_http_unit_test_header_return, NXT_OK }, - { nxt_string("Connection"), - &nxt_http_unit_test_header_return, NXT_OK }, - { nxt_string("Content-Length"), - &nxt_http_unit_test_header_return, NXT_OK }, - { nxt_string("Content-Type"), - &nxt_http_unit_test_header_return, NXT_OK }, - { nxt_string("If-Modified-Since"), - &nxt_http_unit_test_header_return, NXT_OK }, - { nxt_string("If-Match"), - &nxt_http_unit_test_header_return, NXT_OK }, - { nxt_string("Date"), - &nxt_http_unit_test_header_return, NXT_OK }, - { nxt_string("Upgrade"), - &nxt_http_unit_test_header_return, NXT_OK }, - { nxt_string("X-Forwarded-For"), - &nxt_http_unit_test_header_return, NXT_OK }, - { nxt_string("X-Request-ID"), - &nxt_http_unit_test_header_return, NXT_OK }, - - { nxt_null_string, NULL, 0 } -}; - - -static nxt_str_t nxt_http_unit_test_simple_request = nxt_string( - "GET /page HTTP/1.1\r\n" - "Host: example.com\r\n\r\n" -); - - -static nxt_str_t nxt_http_unit_test_big_request = nxt_string( - "POST /path/to/very/interesting/article/on.this.site?arg1=value&arg2=value" - "2&very_big_arg=even_bigger_value HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "User-Agent: Mozilla/5.0 (X11; Gentoo Linux x86_64; rv:42.0) Firefox/42.0" - "\r\n" - "Accept: text/html,application/json,application/xml;q=0.9,*/*;q=0.8\r\n" - "Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4\r\n" - "Accept-Encoding: gzip, deflate, br\r\n" - "If-Modified-Since: Wed, 31 Dec 1986 16:00:00 GMT\r\n" - "Referer: https://example.org/path/to/not-interesting/article.html\r\n" - "Cookie: name=value; name2=value2; some_big_cookie=iVBORw0KGgoAAAANSUhEUgA" - "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\r\n" - "Connection: keep-alive\r\n" - "Content-Length: 0\r\n" - "Upgrade-Insecure-Requests: 1\r\n" - "Pragma: no-cache\r\n" - "Cache-Control: no-cache\r\n" - "X-Forwarded-For: 192.0.2.0, 198.51.100.0, 203.0.113.0\r\n" - "\r\n" -); - - -nxt_int_t -nxt_http_parse_unit_test(nxt_thread_t *thr) -{ - nxt_mp_t *mp, *mp_temp; - nxt_int_t rc; - nxt_uint_t i; - nxt_http_fields_hash_t *hash; - nxt_http_request_parse_t rp; - nxt_http_parse_unit_test_case_t *test; - - nxt_thread_time_update(thr); - - mp = nxt_mp_create(1024, 128, 256, 32); - if (mp == NULL) { - return NXT_ERROR; - } - - hash = nxt_http_fields_hash_create(nxt_http_unit_test_fields, mp); - if (hash == NULL) { - return NXT_ERROR; - } - - for (i = 0; i < nxt_nitems(nxt_http_unit_test_cases); i++) { - test = &nxt_http_unit_test_cases[i]; - - nxt_memzero(&rp, sizeof(nxt_http_request_parse_t)); - - mp_temp = nxt_mp_create(1024, 128, 256, 32); - if (mp_temp == NULL) { - return NXT_ERROR; - } - - if (nxt_http_parse_request_init(&rp, mp_temp) != NXT_OK) { - return NXT_ERROR; - } - - rp.fields_hash = hash; - - rc = nxt_http_parse_unit_test_run(&rp, &test->request); - - if (rc != test->result) { - nxt_log_alert(thr->log, "http parse unit test case failed:\n" - " - request:\n\"%V\"\n" - " - result: %i (expected: %i)", - &test->request, rc, test->result); - return NXT_ERROR; - } - - if (test->handler != NULL - && test->handler(&rp, &test->data, &test->request, thr->log) - != NXT_OK) - { - return NXT_ERROR; - } - - nxt_mp_destroy(mp_temp); - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "http parse unit test passed"); - - hash = nxt_http_fields_hash_create(nxt_http_unit_test_bench_fields, mp); - if (hash == NULL) { - return NXT_ERROR; - } - - if (nxt_http_parse_unit_test_bench(thr, &nxt_http_unit_test_simple_request, - hash, "simple", 10000000) - != NXT_OK) - { - return NXT_ERROR; - } - - if (nxt_http_parse_unit_test_bench(thr, &nxt_http_unit_test_big_request, - hash, "big", 100000) - != NXT_OK) - { - return NXT_ERROR; - } - - nxt_mp_destroy(mp); - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_parse_unit_test_run(nxt_http_request_parse_t *rp, nxt_str_t *request) -{ - nxt_int_t rc; - nxt_buf_mem_t buf; - - buf.start = request->start; - buf.end = request->start + request->length; - - buf.pos = buf.start; - buf.free = buf.pos + 1; - - do { - buf.free++; - rc = nxt_http_parse_request(rp, &buf); - } while (buf.free < buf.end && rc == NXT_AGAIN); - - return rc; -} - - -static nxt_int_t -nxt_http_parse_unit_test_bench(nxt_thread_t *thr, nxt_str_t *request, - nxt_http_fields_hash_t *hash, const char *name, nxt_uint_t n) -{ - nxt_mp_t *mp; - nxt_nsec_t start, end; - nxt_uint_t i; - nxt_buf_mem_t buf; - nxt_http_request_parse_t rp; - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "http parse unit %s request bench started: " - "%uz bytes, %ui runs", - name, request->length, n); - - buf.start = request->start; - buf.end = request->start + request->length; - - nxt_thread_time_update(thr); - start = nxt_thread_monotonic_time(thr); - - for (i = 0; nxt_fast_path(i < n); i++) { - nxt_memzero(&rp, sizeof(nxt_http_request_parse_t)); - - mp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(mp == NULL)) { - return NXT_ERROR; - } - - if (nxt_slow_path(nxt_http_parse_request_init(&rp, mp) != NXT_OK)) { - return NXT_ERROR; - } - - rp.fields_hash = hash; - - buf.pos = buf.start; - buf.free = buf.end; - - if (nxt_slow_path(nxt_http_parse_request(&rp, &buf) != NXT_DONE)) { - nxt_log_alert(thr->log, "http parse unit %s request bench failed " - "while parsing", name); - return NXT_ERROR; - } - - if (nxt_slow_path(nxt_http_fields_process(rp.fields, NULL, thr->log) - != NXT_OK)) - { - nxt_log_alert(thr->log, "http parse unit %s request bench failed " - "while fields processing", name); - return NXT_ERROR; - } - - nxt_mp_destroy(mp); - } - - nxt_thread_time_update(thr); - end = nxt_thread_monotonic_time(thr); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "http parse unit %s request bench: %0.3fs", - name, (end - start) / 1000000000.0); - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_parse_unit_test_request_line(nxt_http_request_parse_t *rp, - nxt_http_parse_unit_test_data_t *data, nxt_str_t *request, nxt_log_t *log) -{ - nxt_str_t str; - - nxt_http_parse_unit_test_request_line_t *test = &data->request_line; - - if (rp->method.start != test->method.start - && !nxt_strstr_eq(&rp->method, &test->method)) - { - nxt_log_alert(log, "http parse unit test case failed:\n" - " - request:\n\"%V\"\n" - " - method: \"%V\" (expected: \"%V\")", - request, &rp->method, &test->method); - return NXT_ERROR; - } - - str.length = rp->target_end - rp->target_start; - str.start = rp->target_start; - - if (str.start != test->target.start - && !nxt_strstr_eq(&str, &test->target)) - { - nxt_log_alert(log, "http parse unit test case failed:\n" - " - request:\n\"%V\"\n" - " - target: \"%V\" (expected: \"%V\")", - request, &str, &test->target); - return NXT_ERROR; - } - - str.length = (rp->exten_start != NULL) ? rp->target_end - rp->exten_start - : 0; - str.start = rp->exten_start; - - if (str.start != test->exten.start - && !nxt_strstr_eq(&str, &test->exten)) - { - nxt_log_alert(log, "http parse unit test case failed:\n" - " - request:\n\"%V\"\n" - " - exten: \"%V\" (expected: \"%V\")", - request, &str, &test->exten); - return NXT_ERROR; - } - - str.length = (rp->args_start != NULL) ? rp->target_end - rp->args_start - : 0; - str.start = rp->args_start; - - if (str.start != test->args.start - && !nxt_strstr_eq(&str, &test->args)) - { - nxt_log_alert(log, "http parse unit test case failed:\n" - " - request:\n\"%V\"\n" - " - args: \"%V\" (expected: \"%V\")", - request, &str, &test->args); - return NXT_ERROR; - } - - if (nxt_memcmp(rp->version.str, test->version, 8) != 0) { - nxt_log_alert(log, "http parse unit test case failed:\n" - " - request:\n\"%V\"\n" - " - version: \"%*s\" (expected: \"%*s\")", - request, 8, rp->version.str, 8, test->version); - return NXT_ERROR; - } - - if (rp->complex_target != test->complex_target) { - nxt_log_alert(log, "http parse unit test case failed:\n" - " - request:\n\"%V\"\n" - " - complex_target: %d (expected: %d)", - request, rp->complex_target, test->complex_target); - return NXT_ERROR; - } - - if (rp->quoted_target != test->quoted_target) { - nxt_log_alert(log, "http parse unit test case failed:\n" - " - request:\n\"%V\"\n" - " - quoted_target: %d (expected: %d)", - request, rp->quoted_target, test->quoted_target); - return NXT_ERROR; - } - - if (rp->space_in_target != test->space_in_target) { - nxt_log_alert(log, "http parse unit test case failed:\n" - " - request:\n\"%V\"\n" - " - space_in_target: %d (expected: %d)", - request, rp->space_in_target, test->space_in_target); - return NXT_ERROR; - } - - if (rp->plus_in_target != test->plus_in_target) { - nxt_log_alert(log, "http parse unit test case failed:\n" - " - request:\n\"%V\"\n" - " - plus_in_target: %d (expected: %d)", - request, rp->plus_in_target, test->plus_in_target); - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_parse_unit_test_fields(nxt_http_request_parse_t *rp, - nxt_http_parse_unit_test_data_t *data, nxt_str_t *request, nxt_log_t *log) -{ - nxt_int_t rc; - - rc = nxt_http_fields_process(rp->fields, NULL, log); - - if (rc != data->result) { - nxt_log_alert(log, "http parse unit test hash failed:\n" - " - request:\n\"%V\"\n" - " - result: %i (expected: %i)", - request, rc, data->result); - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_unit_test_header_return(void *ctx, nxt_http_field_t *field, - nxt_log_t *log) -{ - return (nxt_int_t) field->data; -} diff --git a/test/nxt_lib_unit_test.c b/test/nxt_lib_unit_test.c deleted file mode 100644 index bac2258e..00000000 --- a/test/nxt_lib_unit_test.c +++ /dev/null @@ -1,161 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -extern char **environ; - -nxt_module_init_t nxt_init_modules[1]; -nxt_uint_t nxt_init_modules_n; - - -/* The function is defined here to prevent inline optimizations. */ -static nxt_bool_t -nxt_msec_less(nxt_msec_t first, nxt_msec_t second) -{ - return (nxt_msec_diff(first, second) < 0); -} - - -int nxt_cdecl -main(int argc, char **argv) -{ - nxt_task_t task; - nxt_thread_t *thr; - - if (nxt_lib_start("lib_unit_test", argv, &environ) != NXT_OK) { - return 1; - } - - nxt_main_log.level = NXT_LOG_INFO; - task.log = &nxt_main_log; - - thr = nxt_thread(); - thr->task = &task; - -#if (NXT_UNIT_TEST_RTDTSC) - - if (nxt_process_argv[1] != NULL - && nxt_memcmp(nxt_process_argv[1], "rbm", 3) == 0) - { - if (nxt_rbtree1_mb_start(thr) != NXT_OK) { - return 1; - } - - if (nxt_rbtree_mb_start(thr) != NXT_OK) { - return 1; - } - - if (nxt_lvlhsh_unit_test(thr, 500 * 1000, 0) != NXT_OK) { - return 1; - } - - nxt_rbtree1_mb_insert(thr); - nxt_rbtree_mb_insert(thr); - - if (nxt_lvlhsh_unit_test(thr, 500 * 1000, 0) != NXT_OK) { - return 1; - } - - nxt_rbtree1_mb_delete(thr); - nxt_rbtree_mb_delete(thr); - - return 0; - } - -#endif - - if (nxt_random_unit_test(thr) != NXT_OK) { - return 1; - } - - if (nxt_term_parse_unit_test(thr) != NXT_OK) { - return 1; - } - - if (nxt_msec_diff_unit_test(thr, nxt_msec_less) != NXT_OK) { - return 1; - } - - if (nxt_rbtree_unit_test(thr, 100 * 1000) != NXT_OK) { - return 1; - } - - if (nxt_rbtree_unit_test(thr, 1000 * 1000) != NXT_OK) { - return 1; - } - - if (nxt_rbtree1_unit_test(thr, 100 * 1000) != NXT_OK) { - return 1; - } - - if (nxt_rbtree1_unit_test(thr, 1000 * 1000) != NXT_OK) { - return 1; - } - - if (nxt_mp_unit_test(thr, 100, 40000, 128 - 1) != NXT_OK) { - return 1; - } - - if (nxt_mp_unit_test(thr, 100, 1000, 4096 - 1) != NXT_OK) { - return 1; - } - - if (nxt_mp_unit_test(thr, 1000, 100, 64 * 1024 - 1) != NXT_OK) { - return 1; - } - - if (nxt_mem_zone_unit_test(thr, 100, 20000, 128 - 1) != NXT_OK) { - return 1; - } - - if (nxt_mem_zone_unit_test(thr, 100, 10000, 4096 - 1) != NXT_OK) { - return 1; - } - - if (nxt_mem_zone_unit_test(thr, 1000, 40, 64 * 1024 - 1) != NXT_OK) { - return 1; - } - - if (nxt_lvlhsh_unit_test(thr, 2, 1) != NXT_OK) { - return 1; - } - - if (nxt_lvlhsh_unit_test(thr, 100 * 1000, 1) != NXT_OK) { - return 1; - } - - if (nxt_lvlhsh_unit_test(thr, 100 * 1000, 0) != NXT_OK) { - return 1; - } - - if (nxt_lvlhsh_unit_test(thr, 1000 * 1000, 1) != NXT_OK) { - return 1; - } - - if (nxt_gmtime_unit_test(thr) != NXT_OK) { - return 1; - } - - if (nxt_sprintf_unit_test(thr) != NXT_OK) { - return 1; - } - - if (nxt_malloc_unit_test(thr) != NXT_OK) { - return 1; - } - - if (nxt_utf8_unit_test(thr) != NXT_OK) { - return 1; - } - - if (nxt_http_parse_unit_test(thr) != NXT_OK) { - return 1; - } - - return 0; -} diff --git a/test/nxt_lib_unit_test.h b/test/nxt_lib_unit_test.h deleted file mode 100644 index d215a009..00000000 --- a/test/nxt_lib_unit_test.h +++ /dev/null @@ -1,71 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_LIB_UNIT_TEST_H_INCLUDED_ -#define _NXT_LIB_UNIT_TEST_H_INCLUDED_ - - -#define NXT_LIB_UNIT_TEST_STATIC - - -typedef nxt_bool_t (*nxt_msec_less_t)(nxt_msec_t first, nxt_msec_t second); - - -#define NXT_RBT_NODES 1500 - - -#if (__i386__ || __i386 || __amd64__ || __amd64) -#if (NXT_GCC || NXT_CLANG) - -#define NXT_UNIT_TEST_RTDTSC 1 - -nxt_inline uint64_t -nxt_rdtsc(void) -{ - uint32_t eax, edx; - - __asm__ volatile ("rdtsc" : "=a" (eax), "=d" (edx)); - - return ((uint64_t) edx << 32) | eax; -} - -#endif -#endif - - -nxt_int_t nxt_term_parse_unit_test(nxt_thread_t *thr); -nxt_int_t nxt_msec_diff_unit_test(nxt_thread_t *thr, nxt_msec_less_t); - -nxt_int_t nxt_rbtree_unit_test(nxt_thread_t *thr, nxt_uint_t n); -nxt_int_t nxt_rbtree1_unit_test(nxt_thread_t *thr, nxt_uint_t n); - -#if (NXT_UNIT_TEST_RTDTSC) - -nxt_int_t nxt_rbtree_mb_start(nxt_thread_t *thr); -void nxt_rbtree_mb_insert(nxt_thread_t *thr); -void nxt_rbtree_mb_delete(nxt_thread_t *thr); - -nxt_int_t nxt_rbtree1_mb_start(nxt_thread_t *thr); -void nxt_rbtree1_mb_insert(nxt_thread_t *thr); -void nxt_rbtree1_mb_delete(nxt_thread_t *thr); - -#endif - -nxt_int_t nxt_mp_unit_test(nxt_thread_t *thr, nxt_uint_t runs, - nxt_uint_t nblocks, size_t max_size); -nxt_int_t nxt_mem_zone_unit_test(nxt_thread_t *thr, nxt_uint_t runs, - nxt_uint_t nblocks, size_t max_size); -nxt_int_t nxt_lvlhsh_unit_test(nxt_thread_t *thr, nxt_uint_t n, - nxt_bool_t use_pool); - -nxt_int_t nxt_gmtime_unit_test(nxt_thread_t *thr); -nxt_int_t nxt_sprintf_unit_test(nxt_thread_t *thr); -nxt_int_t nxt_malloc_unit_test(nxt_thread_t *thr); -nxt_int_t nxt_utf8_unit_test(nxt_thread_t *thr); -nxt_int_t nxt_http_parse_unit_test(nxt_thread_t *thr); - - -#endif /* _NXT_LIB_UNIT_TEST_H_INCLUDED_ */ diff --git a/test/nxt_lvlhsh_test.c b/test/nxt_lvlhsh_test.c new file mode 100644 index 00000000..62139fe6 --- /dev/null +++ b/test/nxt_lvlhsh_test.c @@ -0,0 +1,229 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include "nxt_tests.h" + + +static nxt_int_t +nxt_lvlhsh_test_key_test(nxt_lvlhsh_query_t *lhq, void *data) +{ + if (*(uintptr_t *) lhq->key.start == (uintptr_t) data) { + return NXT_OK; + } + + return NXT_DECLINED; +} + + +static void * +nxt_lvlhsh_test_pool_alloc(void *pool, size_t size) +{ + return nxt_mp_align(pool, size, size); +} + + +static void +nxt_lvlhsh_test_pool_free(void *pool, void *p) +{ + nxt_mp_free(pool, p); +} + + +static const nxt_lvlhsh_proto_t malloc_proto nxt_aligned(64) = { + //NXT_LVLHSH_LARGE_MEMALIGN, + NXT_LVLHSH_DEFAULT, + nxt_lvlhsh_test_key_test, + nxt_lvlhsh_alloc, + nxt_lvlhsh_free, +}; + +static const nxt_lvlhsh_proto_t pool_proto nxt_aligned(64) = { + NXT_LVLHSH_LARGE_SLAB, + nxt_lvlhsh_test_key_test, + nxt_lvlhsh_test_pool_alloc, + nxt_lvlhsh_test_pool_free, +}; + + +static nxt_int_t +nxt_lvlhsh_test_add(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto, + void *pool, uintptr_t key) +{ + nxt_lvlhsh_query_t lhq; + + lhq.key_hash = key; + lhq.replace = 0; + lhq.key.length = sizeof(uintptr_t); + lhq.key.start = (u_char *) &key; + lhq.value = (void *) key; + lhq.proto = proto; + lhq.pool = pool; + + switch (nxt_lvlhsh_insert(lh, &lhq)) { + + case NXT_OK: + return NXT_OK; + + case NXT_DECLINED: + nxt_thread_log_alert("lvlhsh test failed: " + "key %p is already in hash", key); + /* Fall through. */ + default: + return NXT_ERROR; + } +} + + +static nxt_int_t +nxt_lvlhsh_test_get(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto, + uintptr_t key) +{ + nxt_lvlhsh_query_t lhq; + + lhq.key_hash = key; + lhq.key.length = sizeof(uintptr_t); + lhq.key.start = (u_char *) &key; + lhq.proto = proto; + + if (nxt_lvlhsh_find(lh, &lhq) == NXT_OK) { + + if (key == (uintptr_t) lhq.value) { + return NXT_OK; + } + } + + nxt_thread_log_alert("lvlhsh test failed: " + "key %p not found in hash", key); + + return NXT_ERROR; +} + + +static nxt_int_t +nxt_lvlhsh_test_delete(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto, + void *pool, uintptr_t key) +{ + nxt_int_t ret; + nxt_lvlhsh_query_t lhq; + + lhq.key_hash = key; + lhq.key.length = sizeof(uintptr_t); + lhq.key.start = (u_char *) &key; + lhq.proto = proto; + lhq.pool = pool; + + ret = nxt_lvlhsh_delete(lh, &lhq); + + if (ret != NXT_OK) { + nxt_thread_log_alert("lvlhsh test failed: " + "key %p not found in hash", key); + } + + return ret; +} + + +nxt_int_t +nxt_lvlhsh_test(nxt_thread_t *thr, nxt_uint_t n, nxt_bool_t use_pool) +{ + uintptr_t key; + nxt_mp_t *mp; + nxt_nsec_t start, end; + nxt_uint_t i; + nxt_lvlhsh_t lh; + nxt_lvlhsh_each_t lhe; + const nxt_lvlhsh_proto_t *proto; + + const size_t min_chunk_size = 32; + const size_t page_size = 1024; + const size_t page_alignment = 128; + const size_t cluster_size = 4096; + + nxt_thread_time_update(thr); + start = nxt_thread_monotonic_time(thr); + + if (use_pool) { + mp = nxt_mp_create(cluster_size, page_alignment, page_size, + min_chunk_size); + if (mp == NULL) { + return NXT_ERROR; + } + + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "lvlhsh test started: %uD pool", n); + proto = &pool_proto; + + } else { + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "lvlhsh test started: %uD malloc", n); + proto = &malloc_proto; + mp = NULL; + } + + nxt_memzero(&lh, sizeof(nxt_lvlhsh_t)); + + key = 0; + for (i = 0; i < n; i++) { + key = nxt_murmur_hash2(&key, sizeof(uint32_t)); + + if (nxt_lvlhsh_test_add(&lh, proto, mp, key) != NXT_OK) { + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "lvlhsh add test failed at %ui", i); + return NXT_ERROR; + } + } + + key = 0; + for (i = 0; i < n; i++) { + key = nxt_murmur_hash2(&key, sizeof(uint32_t)); + + if (nxt_lvlhsh_test_get(&lh, proto, key) != NXT_OK) { + return NXT_ERROR; + } + } + + nxt_memzero(&lhe, sizeof(nxt_lvlhsh_each_t)); + lhe.proto = proto; + + for (i = 0; i < n + 1; i++) { + if (nxt_lvlhsh_each(&lh, &lhe) == NULL) { + break; + } + } + + if (i != n) { + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "lvlhsh each test failed at %ui of %ui", i, n); + return NXT_ERROR; + } + + key = 0; + for (i = 0; i < n; i++) { + key = nxt_murmur_hash2(&key, sizeof(uint32_t)); + + if (nxt_lvlhsh_test_delete(&lh, proto, mp, key) != NXT_OK) { + return NXT_ERROR; + } + } + + if (mp != NULL) { + if (!nxt_mp_is_empty(mp)) { + nxt_log_error(NXT_LOG_NOTICE, thr->log, "mem pool is not empty"); + return NXT_ERROR; + } + + nxt_mp_destroy(mp); + } + + nxt_thread_time_update(thr); + end = nxt_thread_monotonic_time(thr); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "lvlhsh test passed: %0.3fs", + (end - start) / 1000000000.0); + + return NXT_OK; +} diff --git a/test/nxt_lvlhsh_unit_test.c b/test/nxt_lvlhsh_unit_test.c deleted file mode 100644 index 046ee2a5..00000000 --- a/test/nxt_lvlhsh_unit_test.c +++ /dev/null @@ -1,228 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static nxt_int_t -nxt_lvlhsh_unit_test_key_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - if (*(uintptr_t *) lhq->key.start == (uintptr_t) data) { - return NXT_OK; - } - - return NXT_DECLINED; -} - - -static void * -nxt_lvlhsh_unit_test_pool_alloc(void *pool, size_t size) -{ - return nxt_mp_align(pool, size, size); -} - - -static void -nxt_lvlhsh_unit_test_pool_free(void *pool, void *p) -{ - nxt_mp_free(pool, p); -} - - -static const nxt_lvlhsh_proto_t malloc_proto nxt_aligned(64) = { - //NXT_LVLHSH_LARGE_MEMALIGN, - NXT_LVLHSH_DEFAULT, - nxt_lvlhsh_unit_test_key_test, - nxt_lvlhsh_alloc, - nxt_lvlhsh_free, -}; - -static const nxt_lvlhsh_proto_t pool_proto nxt_aligned(64) = { - NXT_LVLHSH_LARGE_SLAB, - nxt_lvlhsh_unit_test_key_test, - nxt_lvlhsh_unit_test_pool_alloc, - nxt_lvlhsh_unit_test_pool_free, -}; - - -static nxt_int_t -nxt_lvlhsh_unit_test_add(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto, - void *pool, uintptr_t key) -{ - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = key; - lhq.replace = 0; - lhq.key.length = sizeof(uintptr_t); - lhq.key.start = (u_char *) &key; - lhq.value = (void *) key; - lhq.proto = proto; - lhq.pool = pool; - - switch (nxt_lvlhsh_insert(lh, &lhq)) { - - case NXT_OK: - return NXT_OK; - - case NXT_DECLINED: - nxt_thread_log_alert("lvlhsh unit test failed: " - "key %p is already in hash", key); - /* Fall through. */ - default: - return NXT_ERROR; - } -} - - -static nxt_int_t -nxt_lvlhsh_unit_test_get(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto, - uintptr_t key) -{ - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = key; - lhq.key.length = sizeof(uintptr_t); - lhq.key.start = (u_char *) &key; - lhq.proto = proto; - - if (nxt_lvlhsh_find(lh, &lhq) == NXT_OK) { - - if (key == (uintptr_t) lhq.value) { - return NXT_OK; - } - } - - nxt_thread_log_alert("lvlhsh unit test failed: " - "key %p not found in hash", key); - - return NXT_ERROR; -} - - -static nxt_int_t -nxt_lvlhsh_unit_test_delete(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto, - void *pool, uintptr_t key) -{ - nxt_int_t ret; - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = key; - lhq.key.length = sizeof(uintptr_t); - lhq.key.start = (u_char *) &key; - lhq.proto = proto; - lhq.pool = pool; - - ret = nxt_lvlhsh_delete(lh, &lhq); - - if (ret != NXT_OK) { - nxt_thread_log_alert("lvlhsh unit test failed: " - "key %p not found in hash", key); - } - - return ret; -} - - -nxt_int_t -nxt_lvlhsh_unit_test(nxt_thread_t *thr, nxt_uint_t n, nxt_bool_t use_pool) -{ - uintptr_t key; - nxt_mp_t *mp; - nxt_nsec_t start, end; - nxt_uint_t i; - nxt_lvlhsh_t lh; - nxt_lvlhsh_each_t lhe; - const nxt_lvlhsh_proto_t *proto; - - const size_t min_chunk_size = 32; - const size_t page_size = 1024; - const size_t page_alignment = 128; - const size_t cluster_size = 4096; - - nxt_thread_time_update(thr); - start = nxt_thread_monotonic_time(thr); - - if (use_pool) { - mp = nxt_mp_create(cluster_size, page_alignment, page_size, - min_chunk_size); - if (mp == NULL) { - return NXT_ERROR; - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "lvlhsh unit test started: %uD pool", n); - proto = &pool_proto; - - } else { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "lvlhsh unit test started: %uD malloc", n); - proto = &malloc_proto; - mp = NULL; - } - - nxt_memzero(&lh, sizeof(nxt_lvlhsh_t)); - - key = 0; - for (i = 0; i < n; i++) { - key = nxt_murmur_hash2(&key, sizeof(uint32_t)); - - if (nxt_lvlhsh_unit_test_add(&lh, proto, mp, key) != NXT_OK) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "lvlhsh add unit test failed at %ui", i); - return NXT_ERROR; - } - } - - key = 0; - for (i = 0; i < n; i++) { - key = nxt_murmur_hash2(&key, sizeof(uint32_t)); - - if (nxt_lvlhsh_unit_test_get(&lh, proto, key) != NXT_OK) { - return NXT_ERROR; - } - } - - nxt_memzero(&lhe, sizeof(nxt_lvlhsh_each_t)); - lhe.proto = proto; - - for (i = 0; i < n + 1; i++) { - if (nxt_lvlhsh_each(&lh, &lhe) == NULL) { - break; - } - } - - if (i != n) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "lvlhsh each unit test failed at %ui of %ui", i, n); - return NXT_ERROR; - } - - key = 0; - for (i = 0; i < n; i++) { - key = nxt_murmur_hash2(&key, sizeof(uint32_t)); - - if (nxt_lvlhsh_unit_test_delete(&lh, proto, mp, key) != NXT_OK) { - return NXT_ERROR; - } - } - - if (mp != NULL) { - if (!nxt_mp_is_empty(mp)) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, "mem pool is not empty"); - return NXT_ERROR; - } - - nxt_mp_destroy(mp); - } - - nxt_thread_time_update(thr); - end = nxt_thread_monotonic_time(thr); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "lvlhsh unit test passed: %0.3fs", - (end - start) / 1000000000.0); - - return NXT_OK; -} diff --git a/test/nxt_malloc_test.c b/test/nxt_malloc_test.c new file mode 100644 index 00000000..daa609b1 --- /dev/null +++ b/test/nxt_malloc_test.c @@ -0,0 +1,123 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include "nxt_tests.h" + + +#define TIMES 1000 + + +typedef struct { + size_t size; + size_t alignment; + nxt_bool_t tight; +} nxt_malloc_size_t; + + +static nxt_malloc_size_t * +nxt_malloc_run_test(nxt_thread_t *thr, nxt_malloc_size_t *last, size_t size, + nxt_uint_t times) +{ + size_t a, s, alignment; + uintptr_t n; + nxt_uint_t i, tight; + static u_char *p[TIMES + 1]; + + alignment = (size_t) -1; + tight = 0; + + for (i = 1; i < times; i++) { + + p[i] = nxt_malloc(size); + if (p[i] == NULL) { + return NULL; + } + + n = (uintptr_t) p[i]; + a = 0; + + while ((n & 1) == 0) { + a++; + n >>= 1; + } + + alignment = nxt_min(alignment, a); + } + + + for (i = 1; i < times; i++) { + s = size; + nxt_malloc_usable_size(p[i], s); + + if (p[i - 1] + s == p[i] || p[i - 1] == p[i] + s) { + tight++; + } + + nxt_free(p[i]); + } + + alignment = 1 << alignment; + +#if 0 + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "malloc: %uz, %uz, %ui", size, alignment, tight); +#endif + + while (last->alignment >= alignment) { + last--; + } + + last++; + + last->size = size; + last->alignment = alignment; + last->tight = times * 9 / 10 < tight; + + return last; +} + + +nxt_int_t +nxt_malloc_test(nxt_thread_t *thr) +{ + size_t size; + nxt_malloc_size_t *last, *s; + static nxt_malloc_size_t sizes[100]; + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "malloc test started"); + + last = &sizes[0]; + + for (size = 1; size < 64; size++) { + last = nxt_malloc_run_test(thr, last, size, TIMES); + if (last == NULL) { + return NXT_ERROR; + } + } + + for (size = 64; size < 16384; size += 8) { + last = nxt_malloc_run_test(thr, last, size, TIMES / 4); + if (last == NULL) { + return NXT_ERROR; + } + } + + for (size = 16384; size < 512 * 1024 + 129; size += 128) { + last = nxt_malloc_run_test(thr, last, size, TIMES / 16); + if (last == NULL) { + return NXT_ERROR; + } + } + + for (s = &sizes[1]; s <= last; s++) { + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "malloc sizes: %uz-%uz alignment:%uz tight:%ui", + s[-1].size + 1, s->size, s->alignment, s->tight); + } + + return NXT_OK; +} diff --git a/test/nxt_malloc_unit_test.c b/test/nxt_malloc_unit_test.c deleted file mode 100644 index f1f67593..00000000 --- a/test/nxt_malloc_unit_test.c +++ /dev/null @@ -1,122 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -#define TIMES 1000 - - -typedef struct { - size_t size; - size_t alignment; - nxt_bool_t tight; -} nxt_malloc_size_t; - - -static nxt_malloc_size_t * -nxt_malloc_test(nxt_thread_t *thr, nxt_malloc_size_t *last, size_t size, - nxt_uint_t times) -{ - size_t a, s, alignment; - uintptr_t n; - nxt_uint_t i, tight; - static u_char *p[TIMES + 1]; - - alignment = (size_t) -1; - tight = 0; - - for (i = 1; i < times; i++) { - - p[i] = nxt_malloc(size); - if (p[i] == NULL) { - return NULL; - } - - n = (uintptr_t) p[i]; - a = 0; - - while ((n & 1) == 0) { - a++; - n >>= 1; - } - - alignment = nxt_min(alignment, a); - } - - - for (i = 1; i < times; i++) { - s = size; - nxt_malloc_usable_size(p[i], s); - - if (p[i - 1] + s == p[i] || p[i - 1] == p[i] + s) { - tight++; - } - - nxt_free(p[i]); - } - - alignment = 1 << alignment; - -#if 0 - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "malloc: %uz, %uz, %ui", size, alignment, tight); -#endif - - while (last->alignment >= alignment) { - last--; - } - - last++; - - last->size = size; - last->alignment = alignment; - last->tight = times * 9 / 10 < tight; - - return last; -} - - -nxt_int_t -nxt_malloc_unit_test(nxt_thread_t *thr) -{ - size_t size; - nxt_malloc_size_t *last, *s; - static nxt_malloc_size_t sizes[100]; - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "malloc test started"); - - last = &sizes[0]; - - for (size = 1; size < 64; size++) { - last = nxt_malloc_test(thr, last, size, TIMES); - if (last == NULL) { - return NXT_ERROR; - } - } - - for (size = 64; size < 16384; size += 8) { - last = nxt_malloc_test(thr, last, size, TIMES / 4); - if (last == NULL) { - return NXT_ERROR; - } - } - - for (size = 16384; size < 512 * 1024 + 129; size += 128) { - last = nxt_malloc_test(thr, last, size, TIMES / 16); - if (last == NULL) { - return NXT_ERROR; - } - } - - for (s = &sizes[1]; s <= last; s++) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "malloc sizes: %uz-%uz alignment:%uz tight:%ui", - s[-1].size + 1, s->size, s->alignment, s->tight); - } - - return NXT_OK; -} diff --git a/test/nxt_mem_zone_test.c b/test/nxt_mem_zone_test.c new file mode 100644 index 00000000..faf0feee --- /dev/null +++ b/test/nxt_mem_zone_test.c @@ -0,0 +1,74 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include "nxt_tests.h" + + +nxt_int_t +nxt_mem_zone_test(nxt_thread_t *thr, nxt_uint_t runs, nxt_uint_t nblocks, + size_t max_size) +{ + void *start, **blocks; + size_t total, zone_size; + uint32_t size; + nxt_uint_t i, n; + nxt_mem_zone_t *zone; + const size_t page_size = 4096; + + nxt_thread_time_update(thr); + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "mem zone test started, max:%uz", max_size); + + zone_size = (max_size + 1) * nblocks; + + start = nxt_memalign(page_size, zone_size); + if (start == NULL) { + return NXT_ERROR; + } + + zone = nxt_mem_zone_init(start, zone_size, page_size); + if (zone == NULL) { + return NXT_ERROR; + } + + blocks = nxt_malloc(nblocks * sizeof(void *)); + if (blocks == NULL) { + return NXT_ERROR; + } + + size = 0; + + for (i = 0; i < runs; i++) { + + total = 0; + + for (n = 0; n < nblocks; n++) { + size = nxt_murmur_hash2(&size, sizeof(uint32_t)); + + total += size & max_size; + blocks[n] = nxt_mem_zone_alloc(zone, size & max_size); + + if (blocks[n] == NULL) { + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "mem zone test failed: %uz", total); + return NXT_ERROR; + } + } + + for (n = 0; n < nblocks; n++) { + nxt_mem_zone_free(zone, blocks[n]); + } + } + + nxt_free(blocks); + nxt_free(zone); + + nxt_thread_time_update(thr); + nxt_log_error(NXT_LOG_NOTICE, thr->log, "mem zone test passed"); + + return NXT_OK; +} diff --git a/test/nxt_mem_zone_unit_test.c b/test/nxt_mem_zone_unit_test.c deleted file mode 100644 index cce9b702..00000000 --- a/test/nxt_mem_zone_unit_test.c +++ /dev/null @@ -1,73 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -nxt_int_t -nxt_mem_zone_unit_test(nxt_thread_t *thr, nxt_uint_t runs, nxt_uint_t nblocks, - size_t max_size) -{ - void *start, **blocks; - size_t total, zone_size; - uint32_t size; - nxt_uint_t i, n; - nxt_mem_zone_t *zone; - const size_t page_size = 4096; - - nxt_thread_time_update(thr); - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "mem zone unit test started, max:%uz", max_size); - - zone_size = (max_size + 1) * nblocks; - - start = nxt_memalign(page_size, zone_size); - if (start == NULL) { - return NXT_ERROR; - } - - zone = nxt_mem_zone_init(start, zone_size, page_size); - if (zone == NULL) { - return NXT_ERROR; - } - - blocks = nxt_malloc(nblocks * sizeof(void *)); - if (blocks == NULL) { - return NXT_ERROR; - } - - size = 0; - - for (i = 0; i < runs; i++) { - - total = 0; - - for (n = 0; n < nblocks; n++) { - size = nxt_murmur_hash2(&size, sizeof(uint32_t)); - - total += size & max_size; - blocks[n] = nxt_mem_zone_alloc(zone, size & max_size); - - if (blocks[n] == NULL) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "mem zone unit test failed: %uz", total); - return NXT_ERROR; - } - } - - for (n = 0; n < nblocks; n++) { - nxt_mem_zone_free(zone, blocks[n]); - } - } - - nxt_free(blocks); - nxt_free(zone); - - nxt_thread_time_update(thr); - nxt_log_error(NXT_LOG_NOTICE, thr->log, "mem zone unit test passed"); - - return NXT_OK; -} diff --git a/test/nxt_mp_test.c b/test/nxt_mp_test.c new file mode 100644 index 00000000..39aa939d --- /dev/null +++ b/test/nxt_mp_test.c @@ -0,0 +1,90 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include "nxt_tests.h" + + +nxt_int_t +nxt_mp_test(nxt_thread_t *thr, nxt_uint_t runs, nxt_uint_t nblocks, + size_t max_size) +{ + void **blocks; + size_t total; + uint32_t value, size; + nxt_mp_t *mp; + nxt_bool_t valid; + nxt_uint_t i, n; + + const size_t min_chunk_size = 16; + const size_t page_size = 128; + const size_t page_alignment = 128; + const size_t cluster_size = page_size * 8; + + nxt_thread_time_update(thr); + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "mem pool test started, max:%uz", max_size); + + blocks = nxt_malloc(nblocks * sizeof(void *)); + if (blocks == NULL) { + return NXT_ERROR; + } + + valid = nxt_mp_test_sizes(cluster_size, page_alignment, page_size, + min_chunk_size); + if (!valid) { + return NXT_ERROR; + } + + mp = nxt_mp_create(cluster_size, page_alignment, page_size, min_chunk_size); + if (mp == NULL) { + return NXT_ERROR; + } + + value = 0; + + for (i = 0; i < runs; i++) { + + total = 0; + + for (n = 0; n < nblocks; n++) { + value = nxt_murmur_hash2(&value, sizeof(uint32_t)); + + size = value & max_size; + + if (size == 0) { + size++; + } + + total += size; + blocks[n] = nxt_mp_alloc(mp, size); + + if (blocks[n] == NULL) { + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "mem pool test failed: %uz", total); + return NXT_ERROR; + } + } + + for (n = 0; n < nblocks; n++) { + nxt_mp_free(mp, blocks[n]); + } + } + + if (!nxt_mp_is_empty(mp)) { + nxt_log_error(NXT_LOG_NOTICE, thr->log, "mem pool is not empty"); + return NXT_ERROR; + } + + nxt_mp_destroy(mp); + + nxt_free(blocks); + + nxt_thread_time_update(thr); + nxt_log_error(NXT_LOG_NOTICE, thr->log, "mem pool test passed"); + + return NXT_OK; +} diff --git a/test/nxt_mp_unit_test.c b/test/nxt_mp_unit_test.c deleted file mode 100644 index c51c9152..00000000 --- a/test/nxt_mp_unit_test.c +++ /dev/null @@ -1,89 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -nxt_int_t -nxt_mp_unit_test(nxt_thread_t *thr, nxt_uint_t runs, nxt_uint_t nblocks, - size_t max_size) -{ - void **blocks; - size_t total; - uint32_t value, size; - nxt_mp_t *mp; - nxt_bool_t valid; - nxt_uint_t i, n; - - const size_t min_chunk_size = 16; - const size_t page_size = 128; - const size_t page_alignment = 128; - const size_t cluster_size = page_size * 8; - - nxt_thread_time_update(thr); - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "mem pool unit test started, max:%uz", max_size); - - blocks = nxt_malloc(nblocks * sizeof(void *)); - if (blocks == NULL) { - return NXT_ERROR; - } - - valid = nxt_mp_test_sizes(cluster_size, page_alignment, page_size, - min_chunk_size); - if (!valid) { - return NXT_ERROR; - } - - mp = nxt_mp_create(cluster_size, page_alignment, page_size, min_chunk_size); - if (mp == NULL) { - return NXT_ERROR; - } - - value = 0; - - for (i = 0; i < runs; i++) { - - total = 0; - - for (n = 0; n < nblocks; n++) { - value = nxt_murmur_hash2(&value, sizeof(uint32_t)); - - size = value & max_size; - - if (size == 0) { - size++; - } - - total += size; - blocks[n] = nxt_mp_alloc(mp, size); - - if (blocks[n] == NULL) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "mem pool unit test failed: %uz", total); - return NXT_ERROR; - } - } - - for (n = 0; n < nblocks; n++) { - nxt_mp_free(mp, blocks[n]); - } - } - - if (!nxt_mp_is_empty(mp)) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, "mem pool is not empty"); - return NXT_ERROR; - } - - nxt_mp_destroy(mp); - - nxt_free(blocks); - - nxt_thread_time_update(thr); - nxt_log_error(NXT_LOG_NOTICE, thr->log, "mem pool unit test passed"); - - return NXT_OK; -} diff --git a/test/nxt_msec_diff_test.c b/test/nxt_msec_diff_test.c new file mode 100644 index 00000000..5af7c011 --- /dev/null +++ b/test/nxt_msec_diff_test.c @@ -0,0 +1,46 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include "nxt_tests.h" + + +static const nxt_msec_t pairs[] = { + + 0x00000000, 0x00000001, + 0x00000000, 0x7fffffff, + + 0x7fffffff, 0x80000000, + 0x7fffffff, 0x80000001, + + 0x80000000, 0x80000001, + 0x80000000, 0xffffffff, + + 0xffffffff, 0x00000000, + 0xffffffff, 0x00000001, +}; + + +nxt_int_t +nxt_msec_diff_test(nxt_thread_t *thr, nxt_msec_less_t less) +{ + nxt_uint_t i; + + nxt_thread_time_update(thr); + + for (i = 0; i < nxt_nitems(pairs); i += 2) { + + if (!less(pairs[i], pairs[i + 1])) { + nxt_log_alert(thr->log, + "msec diff test failed: 0x%08XM 0x%08XM", + pairs[i], pairs[i + 1]); + return NXT_ERROR; + } + } + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "msec diff test passed"); + return NXT_OK; +} diff --git a/test/nxt_msec_diff_unit_test.c b/test/nxt_msec_diff_unit_test.c deleted file mode 100644 index 504cbb5a..00000000 --- a/test/nxt_msec_diff_unit_test.c +++ /dev/null @@ -1,45 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static const nxt_msec_t pairs[] = { - - 0x00000000, 0x00000001, - 0x00000000, 0x7fffffff, - - 0x7fffffff, 0x80000000, - 0x7fffffff, 0x80000001, - - 0x80000000, 0x80000001, - 0x80000000, 0xffffffff, - - 0xffffffff, 0x00000000, - 0xffffffff, 0x00000001, -}; - - -nxt_int_t -nxt_msec_diff_unit_test(nxt_thread_t *thr, nxt_msec_less_t less) -{ - nxt_uint_t i; - - nxt_thread_time_update(thr); - - for (i = 0; i < nxt_nitems(pairs); i += 2) { - - if (!less(pairs[i], pairs[i + 1])) { - nxt_log_alert(thr->log, - "msec diff unit test failed: 0x%08XM 0x%08XM", - pairs[i], pairs[i + 1]); - return NXT_ERROR; - } - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "msec diff unit test passed"); - return NXT_OK; -} diff --git a/test/nxt_rbtree1_test.c b/test/nxt_rbtree1_test.c new file mode 100644 index 00000000..d4783ea1 --- /dev/null +++ b/test/nxt_rbtree1_test.c @@ -0,0 +1,343 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include "nxt_tests.h" +#include "nxt_rbtree1.h" + + +#define \ +nxt_rbtree1_is_empty(tree) \ + (((tree)->root) == (tree)->sentinel) + + +#define \ +nxt_rbtree1_is_there_successor(tree, node) \ + ((node) != (tree)->sentinel) + + +nxt_inline nxt_rbtree1_node_t * +nxt_rbtree1_node_successor(nxt_rbtree1_t *tree, nxt_rbtree1_node_t *node) +{ + nxt_rbtree1_node_t *parent; + + if (node->right != tree->sentinel) { + return nxt_rbtree1_min(node->right, tree->sentinel); + } + + for ( ;; ) { + parent = node->parent; + + if (parent == NULL) { + return tree->sentinel; + } + + if (node == parent->left) { + return parent; + } + + node = parent; + } +} + + +static void nxt_rbtree1_test_insert_value(nxt_rbtree1_node_t *temp, + nxt_rbtree1_node_t *node, nxt_rbtree1_node_t *sentinel); +static nxt_int_t nxt_rbtree1_test_compare(nxt_rbtree1_node_t *node1, + nxt_rbtree1_node_t *node2); +static int nxt_cdecl nxt_rbtree1_test_sort_cmp(const void *one, + const void *two); +static nxt_rbtree1_node_t *nxt_rbtree1_test_find(nxt_rbtree1_t *tree, + nxt_rbtree1_node_t *node); + + +nxt_int_t +nxt_rbtree1_test(nxt_thread_t *thr, nxt_uint_t n) +{ + uint32_t key, *keys; + nxt_uint_t i; + nxt_nsec_t start, end; + nxt_rbtree1_t tree; + nxt_rbtree1_node_t *node, *nodes, sentinel; + + nxt_thread_time_update(thr); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "rbtree1 test started: %ui", n); + + nxt_rbtree1_init(&tree, &sentinel, nxt_rbtree1_test_insert_value); + + nodes = nxt_malloc(n * sizeof(nxt_rbtree1_node_t)); + if (nodes == NULL) { + return NXT_ERROR; + } + + keys = nxt_malloc(n * sizeof(uint32_t)); + if (keys == NULL) { + nxt_free(keys); + return NXT_ERROR; + } + + key = 0; + + for (i = 0; i < n; i++) { + key = nxt_murmur_hash2(&key, sizeof(uint32_t)); + + keys[i] = key; + nodes[i].key = key; + } + + nxt_qsort(keys, n, sizeof(uint32_t), nxt_rbtree1_test_sort_cmp); + + nxt_thread_time_update(thr); + start = nxt_thread_monotonic_time(thr); + + for (i = 0; i < n; i++) { + nxt_rbtree1_insert(&tree, &nodes[i]); + } + + for (i = 0; i < n; i++) { + if (nxt_rbtree1_test_find(&tree, &nodes[i]) != &nodes[i]) { + nxt_log_alert(thr->log, "rbtree1 test failed: %08XD not found", + nodes[i].key); + goto fail; + } + } + + i = 0; + node = nxt_rbtree1_min(tree.root, tree.sentinel); + + while (nxt_rbtree1_is_there_successor(&tree, node)) { + + if (keys[i] != node->key) { + nxt_log_alert(thr->log, "rbtree1 test failed: %i: %08XD %08XD", + i, keys[i], node->key); + goto fail; + } + + i++; + node = nxt_rbtree1_node_successor(&tree, node); + } + + if (i != n) { + nxt_log_alert(thr->log, "rbtree1 test failed: %ui", i); + goto fail; + } + + for (i = 0; i < n; i++) { + nxt_rbtree1_delete(&tree, &nodes[i]); + nxt_memset(&nodes[i], 0xA5, sizeof(nxt_rbtree1_node_t)); + } + + nxt_thread_time_update(thr); + end = nxt_thread_monotonic_time(thr); + + if (!nxt_rbtree1_is_empty(&tree)) { + nxt_log_alert(thr->log, "rbtree1 test failed: tree is not empty"); + goto fail; + } + + nxt_free(keys); + nxt_free(nodes); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "rbtree1 test passed %0.3fs", + (end - start) / 1000000000.0); + + return NXT_OK; + +fail: + + nxt_free(keys); + nxt_free(nodes); + + return NXT_ERROR; +} + + +static void +nxt_rbtree1_test_insert_value(nxt_rbtree1_node_t *temp, + nxt_rbtree1_node_t *node, nxt_rbtree1_node_t *sentinel) +{ + nxt_rbtree1_node_t **p; + + for ( ;; ) { + nxt_prefetch(temp->left); + nxt_prefetch(temp->right); + + p = (node->key < temp->key) ? &temp->left : &temp->right; + + if (*p == sentinel) { + break; + } + + temp = *p; + } + + *p = node; + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + nxt_rbtree1_red(node); +} + + +/* + * Subtraction cannot be used in these comparison functions because the key + * values are spread uniform in whole 0 .. 2^32 range but are not grouped + * around some value as timeout values are. + */ + +nxt_inline nxt_int_t +nxt_rbtree1_test_compare(nxt_rbtree1_node_t *node1, nxt_rbtree1_node_t *node2) +{ + if (node1->key < node2->key) { + return -1; + } + + if (node1->key == node2->key) { + return 0; + } + + return 1; +} + + +static int nxt_cdecl +nxt_rbtree1_test_sort_cmp(const void *one, const void *two) +{ + const uint32_t *first, *second; + + first = one; + second = two; + + if (*first < *second) { + return -1; + } + + if (*first == *second) { + return 0; + } + + return 1; +} + + +static nxt_rbtree1_node_t * +nxt_rbtree1_test_find(nxt_rbtree1_t *tree, nxt_rbtree1_node_t *node) +{ + nxt_int_t n; + nxt_rbtree1_node_t *next, *sentinel; + + next = tree->root; + sentinel = tree->sentinel; + + while (next != sentinel) { + nxt_prefetch(next->left); + nxt_prefetch(next->right); + + n = nxt_rbtree1_test_compare(node, next); + + if (n < 0) { + next = next->left; + + } else if (n > 0) { + next = next->right; + + } else { + return next; + } + } + + return NULL; +} + + +#if (NXT_TEST_RTDTSC) + +#define NXT_RBT_STEP (21 * nxt_pagesize / 10 / sizeof(nxt_rbtree1_node_t)) + +static nxt_rbtree1_t mb_tree; +static nxt_rbtree1_node_t mb_sentinel; +static nxt_rbtree1_node_t *mb_nodes; + + +nxt_int_t +nxt_rbtree1_mb_start(nxt_thread_t *thr) +{ + uint32_t key; + uint64_t start, end; + nxt_uint_t i, n; + + n = NXT_RBT_STEP; + + mb_nodes = nxt_malloc(NXT_RBT_NODES * n * sizeof(nxt_rbtree1_node_t)); + if (mb_nodes == NULL) { + return NXT_ERROR; + } + + nxt_rbtree1_init(&mb_tree, &mb_sentinel, nxt_rbtree1_test_insert_value); + + key = 0; + + for (i = 0; i < NXT_RBT_NODES; i++) { + key = nxt_murmur_hash2(&key, sizeof(uint32_t)); + mb_nodes[n * i].key = key; + } + + for (i = 0; i < NXT_RBT_NODES - 2; i++) { + nxt_rbtree1_insert(&mb_tree, &mb_nodes[n * i]); + } + + n *= (NXT_RBT_NODES - 2); + + start = nxt_rdtsc(); + nxt_rbtree1_insert(&mb_tree, &mb_nodes[n]); + end = nxt_rdtsc(); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "rbtree1 mb cached insert: %L cycles", end - start); + + return NXT_OK; +} + + +void +nxt_rbtree1_mb_insert(nxt_thread_t *thr) +{ + uint64_t start, end; + nxt_uint_t n; + + n = NXT_RBT_STEP; + n *= (NXT_RBT_NODES - 1); + + start = nxt_rdtsc(); + nxt_rbtree1_insert(&mb_tree, &mb_nodes[n]); + end = nxt_rdtsc(); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "rbtree1 mb insert: %L cycles", end - start); +} + + +void +nxt_rbtree1_mb_delete(nxt_thread_t *thr) +{ + uint64_t start, end; + nxt_uint_t n; + + n = NXT_RBT_STEP; + n *= (NXT_RBT_NODES / 4 + 1); + + start = nxt_rdtsc(); + nxt_rbtree1_delete(&mb_tree, &mb_nodes[n]); + end = nxt_rdtsc(); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "rbtree1 mb delete: %L cycles", end - start); + + nxt_free(mb_nodes); +} + +#endif diff --git a/test/nxt_rbtree1_unit_test.c b/test/nxt_rbtree1_unit_test.c deleted file mode 100644 index c3e9f6de..00000000 --- a/test/nxt_rbtree1_unit_test.c +++ /dev/null @@ -1,345 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include "nxt_rbtree1.h" - - -#define \ -nxt_rbtree1_is_empty(tree) \ - (((tree)->root) == (tree)->sentinel) - - -#define \ -nxt_rbtree1_is_there_successor(tree, node) \ - ((node) != (tree)->sentinel) - - -nxt_inline nxt_rbtree1_node_t * -nxt_rbtree1_node_successor(nxt_rbtree1_t *tree, nxt_rbtree1_node_t *node) -{ - nxt_rbtree1_node_t *parent; - - if (node->right != tree->sentinel) { - return nxt_rbtree1_min(node->right, tree->sentinel); - } - - for ( ;; ) { - parent = node->parent; - - if (parent == NULL) { - return tree->sentinel; - } - - if (node == parent->left) { - return parent; - } - - node = parent; - } -} - - -static void nxt_rbtree1_unit_test_insert_value(nxt_rbtree1_node_t *temp, - nxt_rbtree1_node_t *node, nxt_rbtree1_node_t *sentinel); -static nxt_int_t nxt_rbtree1_unit_test_compare(nxt_rbtree1_node_t *node1, - nxt_rbtree1_node_t *node2); -static int nxt_cdecl nxt_rbtree1_unit_test_sort_cmp(const void *one, - const void *two); -static nxt_rbtree1_node_t *nxt_rbtree1_unit_test_find(nxt_rbtree1_t *tree, - nxt_rbtree1_node_t *node); - - -nxt_int_t -nxt_rbtree1_unit_test(nxt_thread_t *thr, nxt_uint_t n) -{ - uint32_t key, *keys; - nxt_uint_t i; - nxt_nsec_t start, end; - nxt_rbtree1_t tree; - nxt_rbtree1_node_t *node, *nodes, sentinel; - - nxt_thread_time_update(thr); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "rbtree1 unit test started: %ui", n); - - nxt_rbtree1_init(&tree, &sentinel, nxt_rbtree1_unit_test_insert_value); - - nodes = nxt_malloc(n * sizeof(nxt_rbtree1_node_t)); - if (nodes == NULL) { - return NXT_ERROR; - } - - keys = nxt_malloc(n * sizeof(uint32_t)); - if (keys == NULL) { - nxt_free(keys); - return NXT_ERROR; - } - - key = 0; - - for (i = 0; i < n; i++) { - key = nxt_murmur_hash2(&key, sizeof(uint32_t)); - - keys[i] = key; - nodes[i].key = key; - } - - nxt_qsort(keys, n, sizeof(uint32_t), nxt_rbtree1_unit_test_sort_cmp); - - nxt_thread_time_update(thr); - start = nxt_thread_monotonic_time(thr); - - for (i = 0; i < n; i++) { - nxt_rbtree1_insert(&tree, &nodes[i]); - } - - for (i = 0; i < n; i++) { - if (nxt_rbtree1_unit_test_find(&tree, &nodes[i]) != &nodes[i]) { - nxt_log_alert(thr->log, "rbtree1 unit test failed: %08XD not found", - nodes[i].key); - goto fail; - } - } - - i = 0; - node = nxt_rbtree1_min(tree.root, tree.sentinel); - - while (nxt_rbtree1_is_there_successor(&tree, node)) { - - if (keys[i] != node->key) { - nxt_log_alert(thr->log, "rbtree1 unit test failed: %i: %08XD %08XD", - i, keys[i], node->key); - goto fail; - } - - i++; - node = nxt_rbtree1_node_successor(&tree, node); - } - - if (i != n) { - nxt_log_alert(thr->log, "rbtree1 unit test failed: %ui", i); - goto fail; - } - - for (i = 0; i < n; i++) { - nxt_rbtree1_delete(&tree, &nodes[i]); - nxt_memset(&nodes[i], 0xA5, sizeof(nxt_rbtree1_node_t)); - } - - nxt_thread_time_update(thr); - end = nxt_thread_monotonic_time(thr); - - if (!nxt_rbtree1_is_empty(&tree)) { - nxt_log_alert(thr->log, "rbtree1 unit test failed: tree is not empty"); - goto fail; - } - - nxt_free(keys); - nxt_free(nodes); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "rbtree1 unit test passed %0.3fs", - (end - start) / 1000000000.0); - - return NXT_OK; - -fail: - - nxt_free(keys); - nxt_free(nodes); - - return NXT_ERROR; -} - - -static void -nxt_rbtree1_unit_test_insert_value(nxt_rbtree1_node_t *temp, - nxt_rbtree1_node_t *node, nxt_rbtree1_node_t *sentinel) -{ - nxt_rbtree1_node_t **p; - - for ( ;; ) { - nxt_prefetch(temp->left); - nxt_prefetch(temp->right); - - p = (node->key < temp->key) ? &temp->left : &temp->right; - - if (*p == sentinel) { - break; - } - - temp = *p; - } - - *p = node; - node->parent = temp; - node->left = sentinel; - node->right = sentinel; - nxt_rbtree1_red(node); -} - - -/* - * Subtraction cannot be used in these comparison functions because the key - * values are spread uniform in whole 0 .. 2^32 range but are not grouped - * around some value as timeout values are. - */ - -nxt_inline nxt_int_t -nxt_rbtree1_unit_test_compare(nxt_rbtree1_node_t *node1, - nxt_rbtree1_node_t *node2) -{ - if (node1->key < node2->key) { - return -1; - } - - if (node1->key == node2->key) { - return 0; - } - - return 1; -} - - -static int nxt_cdecl -nxt_rbtree1_unit_test_sort_cmp(const void *one, const void *two) -{ - const uint32_t *first, *second; - - first = one; - second = two; - - if (*first < *second) { - return -1; - } - - if (*first == *second) { - return 0; - } - - return 1; -} - - -static nxt_rbtree1_node_t * -nxt_rbtree1_unit_test_find(nxt_rbtree1_t *tree, nxt_rbtree1_node_t *node) -{ - nxt_int_t n; - nxt_rbtree1_node_t *next, *sentinel; - - next = tree->root; - sentinel = tree->sentinel; - - while (next != sentinel) { - nxt_prefetch(next->left); - nxt_prefetch(next->right); - - n = nxt_rbtree1_unit_test_compare(node, next); - - if (n < 0) { - next = next->left; - - } else if (n > 0) { - next = next->right; - - } else { - return next; - } - } - - return NULL; -} - - -#if (NXT_UNIT_TEST_RTDTSC) - -#define NXT_RBT_STEP (21 * nxt_pagesize / 10 / sizeof(nxt_rbtree1_node_t)) - -static nxt_rbtree1_t mb_tree; -static nxt_rbtree1_node_t mb_sentinel; -static nxt_rbtree1_node_t *mb_nodes; - - -nxt_int_t -nxt_rbtree1_mb_start(nxt_thread_t *thr) -{ - uint32_t key; - uint64_t start, end; - nxt_uint_t i, n; - - n = NXT_RBT_STEP; - - mb_nodes = nxt_malloc(NXT_RBT_NODES * n * sizeof(nxt_rbtree1_node_t)); - if (mb_nodes == NULL) { - return NXT_ERROR; - } - - nxt_rbtree1_init(&mb_tree, &mb_sentinel, - nxt_rbtree1_unit_test_insert_value); - - key = 0; - - for (i = 0; i < NXT_RBT_NODES; i++) { - key = nxt_murmur_hash2(&key, sizeof(uint32_t)); - mb_nodes[n * i].key = key; - } - - for (i = 0; i < NXT_RBT_NODES - 2; i++) { - nxt_rbtree1_insert(&mb_tree, &mb_nodes[n * i]); - } - - n *= (NXT_RBT_NODES - 2); - - start = nxt_rdtsc(); - nxt_rbtree1_insert(&mb_tree, &mb_nodes[n]); - end = nxt_rdtsc(); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "rbtree1 mb cached insert: %L cycles", end - start); - - return NXT_OK; -} - - -void -nxt_rbtree1_mb_insert(nxt_thread_t *thr) -{ - uint64_t start, end; - nxt_uint_t n; - - n = NXT_RBT_STEP; - n *= (NXT_RBT_NODES - 1); - - start = nxt_rdtsc(); - nxt_rbtree1_insert(&mb_tree, &mb_nodes[n]); - end = nxt_rdtsc(); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "rbtree1 mb insert: %L cycles", end - start); -} - - -void -nxt_rbtree1_mb_delete(nxt_thread_t *thr) -{ - uint64_t start, end; - nxt_uint_t n; - - n = NXT_RBT_STEP; - n *= (NXT_RBT_NODES / 4 + 1); - - start = nxt_rdtsc(); - nxt_rbtree1_delete(&mb_tree, &mb_nodes[n]); - end = nxt_rdtsc(); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "rbtree1 mb delete: %L cycles", end - start); - - nxt_free(mb_nodes); -} - -#endif diff --git a/test/nxt_rbtree_test.c b/test/nxt_rbtree_test.c new file mode 100644 index 00000000..41375d92 --- /dev/null +++ b/test/nxt_rbtree_test.c @@ -0,0 +1,279 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include "nxt_tests.h" + + +typedef struct { + NXT_RBTREE_NODE (node); + uint32_t key; +} nxt_rbtree_test_t; + + +static intptr_t nxt_rbtree_test_comparison(nxt_rbtree_node_t *node1, + nxt_rbtree_node_t *node2); +static nxt_int_t nxt_rbtree_test_compare(uint32_t key1, uint32_t key2); +static int nxt_cdecl nxt_rbtree_test_sort_cmp(const void *one, const void *two); + + +nxt_int_t +nxt_rbtree_test(nxt_thread_t *thr, nxt_uint_t n) +{ + void *mark; + uint32_t key, *keys; + nxt_uint_t i; + nxt_nsec_t start, end; + nxt_rbtree_t tree; + nxt_rbtree_node_t *node; + nxt_rbtree_test_t *items, *item; + + nxt_thread_time_update(thr); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "rbtree test started: %ui", n); + + nxt_rbtree_init(&tree, nxt_rbtree_test_comparison); + + mark = tree.sentinel.right; + + items = nxt_malloc(n * sizeof(nxt_rbtree_test_t)); + if (items == NULL) { + return NXT_ERROR; + } + + keys = nxt_malloc(n * sizeof(uint32_t)); + if (keys == NULL) { + nxt_free(keys); + return NXT_ERROR; + } + + key = 0; + + for (i = 0; i < n; i++) { + key = nxt_murmur_hash2(&key, sizeof(uint32_t)); + + keys[i] = key; + items[i].key = key; + } + + nxt_qsort(keys, n, sizeof(uint32_t), nxt_rbtree_test_sort_cmp); + + nxt_thread_time_update(thr); + start = nxt_thread_monotonic_time(thr); + + for (i = 0; i < n; i++) { + nxt_rbtree_insert(&tree, &items[i].node); + } + + for (i = 0; i < n; i++) { + node = nxt_rbtree_find(&tree, &items[i].node); + + if (node != (nxt_rbtree_node_t *) &items[i].node) { + nxt_log_alert(thr->log, "rbtree test failed: %08XD not found", + items[i].key); + goto fail; + } + } + + i = 0; + node = nxt_rbtree_min(&tree); + + while (nxt_rbtree_is_there_successor(&tree, node)) { + + item = (nxt_rbtree_test_t *) node; + + if (keys[i] != item->key) { + nxt_log_alert(thr->log, "rbtree test failed: %i: %08XD %08XD", + i, keys[i], item->key); + goto fail; + } + + i++; + node = nxt_rbtree_node_successor(&tree, node); + } + + if (i != n) { + nxt_log_alert(thr->log, "rbtree test failed: %ui", i); + goto fail; + } + + for (i = 0; i < n; i++) { + nxt_rbtree_delete(&tree, &items[i].node); + nxt_memset(&items[i], 0xA5, sizeof(nxt_rbtree_test_t)); + } + + nxt_thread_time_update(thr); + end = nxt_thread_monotonic_time(thr); + + if (!nxt_rbtree_is_empty(&tree)) { + nxt_log_alert(thr->log, "rbtree test failed: tree is not empty"); + goto fail; + } + + /* Check that the sentinel callback was not modified. */ + + if (mark != tree.sentinel.right) { + nxt_log_alert(thr->log, "rbtree sentinel test failed"); + goto fail; + } + + nxt_free(keys); + nxt_free(items); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "rbtree test passed %0.3fs", + (end - start) / 1000000000.0); + + return NXT_OK; + +fail: + + nxt_free(keys); + nxt_free(items); + + return NXT_ERROR; +} + + +static intptr_t +nxt_rbtree_test_comparison(nxt_rbtree_node_t *node1, + nxt_rbtree_node_t *node2) +{ + nxt_rbtree_test_t *item1, *item2; + + item1 = (nxt_rbtree_test_t *) node1; + item2 = (nxt_rbtree_test_t *) node2; + + return nxt_rbtree_test_compare(item1->key, item2->key); +} + + +/* + * Subtraction cannot be used in these comparison functions because + * the key values are spread uniform in whole 0 .. 2^32 range but are + * not grouped around some value as timeout values are. + */ + +static nxt_int_t +nxt_rbtree_test_compare(uint32_t key1, uint32_t key2) +{ + if (key1 < key2) { + return -1; + } + + if (key1 == key2) { + return 0; + } + + return 1; +} + + +static int nxt_cdecl +nxt_rbtree_test_sort_cmp(const void *one, const void *two) +{ + const uint32_t *first, *second; + + first = one; + second = two; + + if (*first < *second) { + return -1; + } + + if (*first == *second) { + return 0; + } + + return 1; +} + + +#if (NXT_TEST_RTDTSC) + +#define NXT_RBT_STEP (21 * nxt_pagesize / 10 / sizeof(nxt_rbtree_test_t)) + +static nxt_rbtree_t mb_tree; +static nxt_rbtree_test_t *mb_nodes; + + +nxt_int_t +nxt_rbtree_mb_start(nxt_thread_t *thr) +{ + uint32_t key; + uint64_t start, end; + nxt_uint_t i, n; + + n = NXT_RBT_STEP; + + mb_nodes = nxt_malloc(NXT_RBT_NODES * n * sizeof(nxt_rbtree_test_t)); + if (mb_nodes == NULL) { + return NXT_ERROR; + } + + nxt_rbtree_init(&mb_tree, nxt_rbtree_test_comparison); + + key = 0; + + for (i = 0; i < NXT_RBT_NODES; i++) { + key = nxt_murmur_hash2(&key, sizeof(uint32_t)); + mb_nodes[n * i].key = key; + } + + for (i = 0; i < NXT_RBT_NODES - 2; i++) { + nxt_rbtree_insert(&mb_tree, &mb_nodes[n * i].node); + } + + n *= (NXT_RBT_NODES - 2); + + start = nxt_rdtsc(); + nxt_rbtree_insert(&mb_tree, &mb_nodes[n].node); + end = nxt_rdtsc(); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "rbtree mb cached insert: %L cycles", end - start); + + return NXT_OK; +} + + +void +nxt_rbtree_mb_insert(nxt_thread_t *thr) +{ + uint64_t start, end; + nxt_uint_t n; + + n = NXT_RBT_STEP; + n *= (NXT_RBT_NODES - 1); + + start = nxt_rdtsc(); + nxt_rbtree_insert(&mb_tree, &mb_nodes[n].node); + end = nxt_rdtsc(); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "rbtree mb insert: %L cycles", end - start); +} + + +void +nxt_rbtree_mb_delete(nxt_thread_t *thr) +{ + uint64_t start, end; + nxt_uint_t n; + + n = NXT_RBT_STEP; + n *= (NXT_RBT_NODES / 4 + 1); + + start = nxt_rdtsc(); + nxt_rbtree_delete(&mb_tree, &mb_nodes[n].node); + end = nxt_rdtsc(); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "rbtree mb delete: %L cycles", end - start); + + nxt_free(mb_nodes); +} + +#endif diff --git a/test/nxt_rbtree_unit_test.c b/test/nxt_rbtree_unit_test.c deleted file mode 100644 index 9f38d2c3..00000000 --- a/test/nxt_rbtree_unit_test.c +++ /dev/null @@ -1,279 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -typedef struct { - NXT_RBTREE_NODE (node); - uint32_t key; -} nxt_rbtree_test_t; - - -static intptr_t nxt_rbtree_unit_test_comparison(nxt_rbtree_node_t *node1, - nxt_rbtree_node_t *node2); -static nxt_int_t nxt_rbtree_unit_test_compare(uint32_t key1, uint32_t key2); -static int nxt_cdecl nxt_rbtree_unit_test_sort_cmp(const void *one, - const void *two); - - -nxt_int_t -nxt_rbtree_unit_test(nxt_thread_t *thr, nxt_uint_t n) -{ - void *mark; - uint32_t key, *keys; - nxt_uint_t i; - nxt_nsec_t start, end; - nxt_rbtree_t tree; - nxt_rbtree_node_t *node; - nxt_rbtree_test_t *items, *item; - - nxt_thread_time_update(thr); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "rbtree unit test started: %ui", n); - - nxt_rbtree_init(&tree, nxt_rbtree_unit_test_comparison); - - mark = tree.sentinel.right; - - items = nxt_malloc(n * sizeof(nxt_rbtree_test_t)); - if (items == NULL) { - return NXT_ERROR; - } - - keys = nxt_malloc(n * sizeof(uint32_t)); - if (keys == NULL) { - nxt_free(keys); - return NXT_ERROR; - } - - key = 0; - - for (i = 0; i < n; i++) { - key = nxt_murmur_hash2(&key, sizeof(uint32_t)); - - keys[i] = key; - items[i].key = key; - } - - nxt_qsort(keys, n, sizeof(uint32_t), nxt_rbtree_unit_test_sort_cmp); - - nxt_thread_time_update(thr); - start = nxt_thread_monotonic_time(thr); - - for (i = 0; i < n; i++) { - nxt_rbtree_insert(&tree, &items[i].node); - } - - for (i = 0; i < n; i++) { - node = nxt_rbtree_find(&tree, &items[i].node); - - if (node != (nxt_rbtree_node_t *) &items[i].node) { - nxt_log_alert(thr->log, "rbtree unit test failed: %08XD not found", - items[i].key); - goto fail; - } - } - - i = 0; - node = nxt_rbtree_min(&tree); - - while (nxt_rbtree_is_there_successor(&tree, node)) { - - item = (nxt_rbtree_test_t *) node; - - if (keys[i] != item->key) { - nxt_log_alert(thr->log, "rbtree unit test failed: %i: %08XD %08XD", - i, keys[i], item->key); - goto fail; - } - - i++; - node = nxt_rbtree_node_successor(&tree, node); - } - - if (i != n) { - nxt_log_alert(thr->log, "rbtree unit test failed: %ui", i); - goto fail; - } - - for (i = 0; i < n; i++) { - nxt_rbtree_delete(&tree, &items[i].node); - nxt_memset(&items[i], 0xA5, sizeof(nxt_rbtree_test_t)); - } - - nxt_thread_time_update(thr); - end = nxt_thread_monotonic_time(thr); - - if (!nxt_rbtree_is_empty(&tree)) { - nxt_log_alert(thr->log, "rbtree unit test failed: tree is not empty"); - goto fail; - } - - /* Check that the sentinel callback was not modified. */ - - if (mark != tree.sentinel.right) { - nxt_log_alert(thr->log, "rbtree sentinel unit test failed"); - goto fail; - } - - nxt_free(keys); - nxt_free(items); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "rbtree unit test passed %0.3fs", - (end - start) / 1000000000.0); - - return NXT_OK; - -fail: - - nxt_free(keys); - nxt_free(items); - - return NXT_ERROR; -} - - -static intptr_t -nxt_rbtree_unit_test_comparison(nxt_rbtree_node_t *node1, - nxt_rbtree_node_t *node2) -{ - nxt_rbtree_test_t *item1, *item2; - - item1 = (nxt_rbtree_test_t *) node1; - item2 = (nxt_rbtree_test_t *) node2; - - return nxt_rbtree_unit_test_compare(item1->key, item2->key); -} - - -/* - * Subtraction cannot be used in these comparison functions because - * the key values are spread uniform in whole 0 .. 2^32 range but are - * not grouped around some value as timeout values are. - */ - -static nxt_int_t -nxt_rbtree_unit_test_compare(uint32_t key1, uint32_t key2) -{ - if (key1 < key2) { - return -1; - } - - if (key1 == key2) { - return 0; - } - - return 1; -} - - -static int nxt_cdecl -nxt_rbtree_unit_test_sort_cmp(const void *one, const void *two) -{ - const uint32_t *first, *second; - - first = one; - second = two; - - if (*first < *second) { - return -1; - } - - if (*first == *second) { - return 0; - } - - return 1; -} - - -#if (NXT_UNIT_TEST_RTDTSC) - -#define NXT_RBT_STEP (21 * nxt_pagesize / 10 / sizeof(nxt_rbtree_test_t)) - -static nxt_rbtree_t mb_tree; -static nxt_rbtree_test_t *mb_nodes; - - -nxt_int_t -nxt_rbtree_mb_start(nxt_thread_t *thr) -{ - uint32_t key; - uint64_t start, end; - nxt_uint_t i, n; - - n = NXT_RBT_STEP; - - mb_nodes = nxt_malloc(NXT_RBT_NODES * n * sizeof(nxt_rbtree_test_t)); - if (mb_nodes == NULL) { - return NXT_ERROR; - } - - nxt_rbtree_init(&mb_tree, nxt_rbtree_unit_test_comparison); - - key = 0; - - for (i = 0; i < NXT_RBT_NODES; i++) { - key = nxt_murmur_hash2(&key, sizeof(uint32_t)); - mb_nodes[n * i].key = key; - } - - for (i = 0; i < NXT_RBT_NODES - 2; i++) { - nxt_rbtree_insert(&mb_tree, &mb_nodes[n * i].node); - } - - n *= (NXT_RBT_NODES - 2); - - start = nxt_rdtsc(); - nxt_rbtree_insert(&mb_tree, &mb_nodes[n].node); - end = nxt_rdtsc(); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "rbtree mb cached insert: %L cycles", end - start); - - return NXT_OK; -} - - -void -nxt_rbtree_mb_insert(nxt_thread_t *thr) -{ - uint64_t start, end; - nxt_uint_t n; - - n = NXT_RBT_STEP; - n *= (NXT_RBT_NODES - 1); - - start = nxt_rdtsc(); - nxt_rbtree_insert(&mb_tree, &mb_nodes[n].node); - end = nxt_rdtsc(); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "rbtree mb insert: %L cycles", end - start); -} - - -void -nxt_rbtree_mb_delete(nxt_thread_t *thr) -{ - uint64_t start, end; - nxt_uint_t n; - - n = NXT_RBT_STEP; - n *= (NXT_RBT_NODES / 4 + 1); - - start = nxt_rdtsc(); - nxt_rbtree_delete(&mb_tree, &mb_nodes[n].node); - end = nxt_rdtsc(); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "rbtree mb delete: %L cycles", end - start); - - nxt_free(mb_nodes); -} - -#endif diff --git a/test/nxt_sprintf_test.c b/test/nxt_sprintf_test.c new file mode 100644 index 00000000..7c6e2019 --- /dev/null +++ b/test/nxt_sprintf_test.c @@ -0,0 +1,71 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include "nxt_tests.h" + + +typedef struct { + const char *format; + const char *test; + double number; +} nxt_sprintf_double_test_t; + + +static const nxt_sprintf_double_test_t double_test[] = +{ + { "%3.5f", "1234.56700", 1234.567 }, + { "%3.0f", "1234", 1234.567 }, + { "%f", "1234.567", 1234.567 }, + { "%f", "0.1", 0.1 }, + { "%f", "0.000001", 0.000001 }, + { "%f", "4503599627370495", 4503599627370495.0 }, +}; + + +static nxt_int_t +nxt_sprintf_test_double(u_char *buf, u_char *end, const char *fmt, + const char *test, double n) +{ + u_char *p; + + p = nxt_sprintf(buf, end, fmt, n); + *p = '\0'; + + return nxt_strcmp(buf, test); +} + + +nxt_int_t +nxt_sprintf_test(nxt_thread_t *thr) +{ + nxt_int_t ret; + nxt_uint_t i; + u_char *end, buf[64]; + + nxt_thread_time_update(thr); + + end = buf + 64; + + for (i = 0; i < nxt_nitems(double_test); i++) { + + ret = nxt_sprintf_test_double(buf, end, double_test[i].format, + double_test[i].test, + double_test[i].number); + + if (ret == NXT_OK) { + continue; + } + + nxt_log_alert(thr->log, "nxt_sprintf(\"%s\") failed: \"%s\" vs \"%s\"", + double_test[i].format, double_test[i].test, buf); + + return NXT_ERROR; + } + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "nxt_sprintf() test passed"); + return NXT_OK; +} diff --git a/test/nxt_sprintf_unit_test.c b/test/nxt_sprintf_unit_test.c deleted file mode 100644 index 02434791..00000000 --- a/test/nxt_sprintf_unit_test.c +++ /dev/null @@ -1,70 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -typedef struct { - const char *format; - const char *test; - double number; -} nxt_sprintf_double_test_t; - - -static const nxt_sprintf_double_test_t double_test[] = -{ - { "%3.5f", "1234.56700", 1234.567 }, - { "%3.0f", "1234", 1234.567 }, - { "%f", "1234.567", 1234.567 }, - { "%f", "0.1", 0.1 }, - { "%f", "0.000001", 0.000001 }, - { "%f", "4503599627370495", 4503599627370495.0 }, -}; - - -static nxt_int_t -nxt_sprintf_test_double(u_char *buf, u_char *end, const char *fmt, - const char *test, double n) -{ - u_char *p; - - p = nxt_sprintf(buf, end, fmt, n); - *p = '\0'; - - return nxt_strcmp(buf, test); -} - - -nxt_int_t -nxt_sprintf_unit_test(nxt_thread_t *thr) -{ - nxt_int_t ret; - nxt_uint_t i; - u_char *end, buf[64]; - - nxt_thread_time_update(thr); - - end = buf + 64; - - for (i = 0; i < nxt_nitems(double_test); i++) { - - ret = nxt_sprintf_test_double(buf, end, double_test[i].format, - double_test[i].test, - double_test[i].number); - - if (ret == NXT_OK) { - continue; - } - - nxt_log_alert(thr->log, "nxt_sprintf(\"%s\") failed: \"%s\" vs \"%s\"", - double_test[i].format, double_test[i].test, buf); - - return NXT_ERROR; - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "nxt_sprintf() unit test passed"); - return NXT_OK; -} diff --git a/test/nxt_term_parse_test.c b/test/nxt_term_parse_test.c new file mode 100644 index 00000000..83ae4931 --- /dev/null +++ b/test/nxt_term_parse_test.c @@ -0,0 +1,60 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include "nxt_tests.h" + + +typedef struct { + nxt_str_t string; + nxt_bool_t is_sec; + nxt_int_t value; +} nxt_term_parse_test_t; + + +static const nxt_term_parse_test_t terms[] = { + { nxt_string("1y"), 1, 365 * 24 * 60 * 60 }, + { nxt_string("1w"), 1, 7 * 24 * 60 * 60 }, + { nxt_string("1w"), 0, 7 * 24 * 60 * 60 * 1000 }, + { nxt_string("1w 1d"), 0, 8 * 24 * 60 * 60 * 1000 }, + { nxt_string("1w d"), 0, -1 }, + { nxt_string("w"), 0, -1 }, + { nxt_string("1d 1w"), 0, -1 }, + { nxt_string("25d"), 0, -2 }, + { nxt_string("300"), 1, 300 }, + { nxt_string("300"), 0, 300000 }, + { nxt_string("300s"), 1, 300 }, + { nxt_string("300ms"), 0, 300 }, + { nxt_string("1y 1M 1w1d1h1m1s"), 1, + (((((365 + 30 + 7 + 1) * 24 + 1) * 60) + 1) * 60) + 1 }, +}; + + +nxt_int_t +nxt_term_parse_test(nxt_thread_t *thr) +{ + nxt_int_t val; + nxt_uint_t i; + const nxt_str_t *s; + + nxt_thread_time_update(thr); + + for (i = 0; i < nxt_nitems(terms); i++) { + + s = &terms[i].string; + val = nxt_term_parse(s->start, s->length, terms[i].is_sec); + + if (val != terms[i].value) { + nxt_log_alert(thr->log, + "term parse test failed: \"%V\": %i %i", + s, terms[i].value, val); + return NXT_ERROR; + } + } + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "term parse test passed"); + return NXT_OK; +} diff --git a/test/nxt_term_parse_unit_test.c b/test/nxt_term_parse_unit_test.c deleted file mode 100644 index 818d0e19..00000000 --- a/test/nxt_term_parse_unit_test.c +++ /dev/null @@ -1,59 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -typedef struct { - nxt_str_t string; - nxt_bool_t is_sec; - nxt_int_t value; -} nxt_term_parse_test_t; - - -static const nxt_term_parse_test_t terms[] = { - { nxt_string("1y"), 1, 365 * 24 * 60 * 60 }, - { nxt_string("1w"), 1, 7 * 24 * 60 * 60 }, - { nxt_string("1w"), 0, 7 * 24 * 60 * 60 * 1000 }, - { nxt_string("1w 1d"), 0, 8 * 24 * 60 * 60 * 1000 }, - { nxt_string("1w d"), 0, -1 }, - { nxt_string("w"), 0, -1 }, - { nxt_string("1d 1w"), 0, -1 }, - { nxt_string("25d"), 0, -2 }, - { nxt_string("300"), 1, 300 }, - { nxt_string("300"), 0, 300000 }, - { nxt_string("300s"), 1, 300 }, - { nxt_string("300ms"), 0, 300 }, - { nxt_string("1y 1M 1w1d1h1m1s"), 1, - (((((365 + 30 + 7 + 1) * 24 + 1) * 60) + 1) * 60) + 1 }, -}; - - -nxt_int_t -nxt_term_parse_unit_test(nxt_thread_t *thr) -{ - nxt_int_t val; - nxt_uint_t i; - const nxt_str_t *s; - - nxt_thread_time_update(thr); - - for (i = 0; i < nxt_nitems(terms); i++) { - - s = &terms[i].string; - val = nxt_term_parse(s->start, s->length, terms[i].is_sec); - - if (val != terms[i].value) { - nxt_log_alert(thr->log, - "term parse unit test failed: \"%V\": %i %i", - s, terms[i].value, val); - return NXT_ERROR; - } - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "term parse unit test passed"); - return NXT_OK; -} diff --git a/test/nxt_tests.c b/test/nxt_tests.c new file mode 100644 index 00000000..655192ab --- /dev/null +++ b/test/nxt_tests.c @@ -0,0 +1,162 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include "nxt_tests.h" + + +extern char **environ; + +nxt_module_init_t nxt_init_modules[1]; +nxt_uint_t nxt_init_modules_n; + + +/* The function is defined here to prevent inline optimizations. */ +static nxt_bool_t +nxt_msec_less(nxt_msec_t first, nxt_msec_t second) +{ + return (nxt_msec_diff(first, second) < 0); +} + + +int nxt_cdecl +main(int argc, char **argv) +{ + nxt_task_t task; + nxt_thread_t *thr; + + if (nxt_lib_start("tests", argv, &environ) != NXT_OK) { + return 1; + } + + nxt_main_log.level = NXT_LOG_INFO; + task.log = &nxt_main_log; + + thr = nxt_thread(); + thr->task = &task; + +#if (NXT_TEST_RTDTSC) + + if (nxt_process_argv[1] != NULL + && nxt_memcmp(nxt_process_argv[1], "rbm", 3) == 0) + { + if (nxt_rbtree1_mb_start(thr) != NXT_OK) { + return 1; + } + + if (nxt_rbtree_mb_start(thr) != NXT_OK) { + return 1; + } + + if (nxt_lvlhsh_test(thr, 500 * 1000, 0) != NXT_OK) { + return 1; + } + + nxt_rbtree1_mb_insert(thr); + nxt_rbtree_mb_insert(thr); + + if (nxt_lvlhsh_test(thr, 500 * 1000, 0) != NXT_OK) { + return 1; + } + + nxt_rbtree1_mb_delete(thr); + nxt_rbtree_mb_delete(thr); + + return 0; + } + +#endif + + if (nxt_random_test(thr) != NXT_OK) { + return 1; + } + + if (nxt_term_parse_test(thr) != NXT_OK) { + return 1; + } + + if (nxt_msec_diff_test(thr, nxt_msec_less) != NXT_OK) { + return 1; + } + + if (nxt_rbtree_test(thr, 100 * 1000) != NXT_OK) { + return 1; + } + + if (nxt_rbtree_test(thr, 1000 * 1000) != NXT_OK) { + return 1; + } + + if (nxt_rbtree1_test(thr, 100 * 1000) != NXT_OK) { + return 1; + } + + if (nxt_rbtree1_test(thr, 1000 * 1000) != NXT_OK) { + return 1; + } + + if (nxt_mp_test(thr, 100, 40000, 128 - 1) != NXT_OK) { + return 1; + } + + if (nxt_mp_test(thr, 100, 1000, 4096 - 1) != NXT_OK) { + return 1; + } + + if (nxt_mp_test(thr, 1000, 100, 64 * 1024 - 1) != NXT_OK) { + return 1; + } + + if (nxt_mem_zone_test(thr, 100, 20000, 128 - 1) != NXT_OK) { + return 1; + } + + if (nxt_mem_zone_test(thr, 100, 10000, 4096 - 1) != NXT_OK) { + return 1; + } + + if (nxt_mem_zone_test(thr, 1000, 40, 64 * 1024 - 1) != NXT_OK) { + return 1; + } + + if (nxt_lvlhsh_test(thr, 2, 1) != NXT_OK) { + return 1; + } + + if (nxt_lvlhsh_test(thr, 100 * 1000, 1) != NXT_OK) { + return 1; + } + + if (nxt_lvlhsh_test(thr, 100 * 1000, 0) != NXT_OK) { + return 1; + } + + if (nxt_lvlhsh_test(thr, 1000 * 1000, 1) != NXT_OK) { + return 1; + } + + if (nxt_gmtime_test(thr) != NXT_OK) { + return 1; + } + + if (nxt_sprintf_test(thr) != NXT_OK) { + return 1; + } + + if (nxt_malloc_test(thr) != NXT_OK) { + return 1; + } + + if (nxt_utf8_test(thr) != NXT_OK) { + return 1; + } + + if (nxt_http_parse_test(thr) != NXT_OK) { + return 1; + } + + return 0; +} diff --git a/test/nxt_tests.h b/test/nxt_tests.h new file mode 100644 index 00000000..508ddbe4 --- /dev/null +++ b/test/nxt_tests.h @@ -0,0 +1,68 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#ifndef _NXT_TESTS_H_INCLUDED_ +#define _NXT_TESTS_H_INCLUDED_ + + +typedef nxt_bool_t (*nxt_msec_less_t)(nxt_msec_t first, nxt_msec_t second); + + +#define NXT_RBT_NODES 1500 + + +#if (__i386__ || __i386 || __amd64__ || __amd64) +#if (NXT_GCC || NXT_CLANG) + +#define NXT_TEST_RTDTSC 1 + +nxt_inline uint64_t +nxt_rdtsc(void) +{ + uint32_t eax, edx; + + __asm__ volatile ("rdtsc" : "=a" (eax), "=d" (edx)); + + return ((uint64_t) edx << 32) | eax; +} + +#endif +#endif + + +nxt_int_t nxt_term_parse_test(nxt_thread_t *thr); +nxt_int_t nxt_msec_diff_test(nxt_thread_t *thr, nxt_msec_less_t); + +nxt_int_t nxt_rbtree_test(nxt_thread_t *thr, nxt_uint_t n); +nxt_int_t nxt_rbtree1_test(nxt_thread_t *thr, nxt_uint_t n); + +#if (NXT_TEST_RTDTSC) + +nxt_int_t nxt_rbtree_mb_start(nxt_thread_t *thr); +void nxt_rbtree_mb_insert(nxt_thread_t *thr); +void nxt_rbtree_mb_delete(nxt_thread_t *thr); + +nxt_int_t nxt_rbtree1_mb_start(nxt_thread_t *thr); +void nxt_rbtree1_mb_insert(nxt_thread_t *thr); +void nxt_rbtree1_mb_delete(nxt_thread_t *thr); + +#endif + +nxt_int_t nxt_mp_test(nxt_thread_t *thr, nxt_uint_t runs, nxt_uint_t nblocks, + size_t max_size); +nxt_int_t nxt_mem_zone_test(nxt_thread_t *thr, nxt_uint_t runs, + nxt_uint_t nblocks, size_t max_size); +nxt_int_t nxt_lvlhsh_test(nxt_thread_t *thr, nxt_uint_t n, + nxt_bool_t use_pool); + +nxt_int_t nxt_gmtime_test(nxt_thread_t *thr); +nxt_int_t nxt_sprintf_test(nxt_thread_t *thr); +nxt_int_t nxt_malloc_test(nxt_thread_t *thr); +nxt_int_t nxt_utf8_test(nxt_thread_t *thr); +nxt_int_t nxt_http_parse_test(nxt_thread_t *thr); + + +#endif /* _NXT_TESTS_H_INCLUDED_ */ diff --git a/test/nxt_utf8_file_name_test.c b/test/nxt_utf8_file_name_test.c index 9eccc147..dc08f7e5 100644 --- a/test/nxt_utf8_file_name_test.c +++ b/test/nxt_utf8_file_name_test.c @@ -140,6 +140,6 @@ nxt_utf8_file_name_test(nxt_thread_t *thr) nxt_file_delete(uc_file.name); } - nxt_log_error(NXT_LOG_NOTICE, thr->log, "utf8 file name unit test passed"); + nxt_log_error(NXT_LOG_NOTICE, thr->log, "utf8 file name test passed"); return NXT_OK; } diff --git a/test/nxt_utf8_test.c b/test/nxt_utf8_test.c new file mode 100644 index 00000000..c7323876 --- /dev/null +++ b/test/nxt_utf8_test.c @@ -0,0 +1,191 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include "nxt_tests.h" + + +#define NXT_UTF8_START_TEST 0xc2 +//#define NXT_UTF8_START_TEST 0 + + +static u_char invalid[] = { + + /* Invalid first byte less than 0xc2. */ + 1, 0x80, 0x00, 0x00, 0x00, + 1, 0xc0, 0x00, 0x00, 0x00, + 2, 0xc0, 0x00, 0x00, 0x00, + 3, 0xc0, 0x00, 0x00, 0x00, + 4, 0xc0, 0x00, 0x00, 0x00, + + /* Invalid 0x0x110000 value. */ + 4, 0xf4, 0x90, 0x80, 0x80, + + /* Incomplete length. */ + 2, 0xe0, 0xaf, 0xb5, 0x00, + + /* Overlong values. */ + 2, 0xc0, 0x80, 0x00, 0x00, + 2, 0xc1, 0xb3, 0x00, 0x00, + 3, 0xe0, 0x80, 0x80, 0x00, + 3, 0xe0, 0x81, 0xb3, 0x00, + 3, 0xe0, 0x90, 0x9a, 0x00, + 4, 0xf0, 0x80, 0x8a, 0x80, + 4, 0xf0, 0x80, 0x81, 0xb3, + 4, 0xf0, 0x80, 0xaf, 0xb5, +}; + + +static nxt_int_t +nxt_utf8_overlong(nxt_thread_t *thr, u_char *overlong, size_t len) +{ + u_char *p, utf8[4]; + size_t size; + uint32_t u, d; + nxt_uint_t i; + const u_char *pp; + + pp = overlong; + + d = nxt_utf8_decode(&pp, overlong + len); + + len = pp - overlong; + + if (d != 0xffffffff) { + p = nxt_utf8_encode(utf8, d); + + size = (p != NULL) ? p - utf8 : 0; + + if (len != size || nxt_memcmp(overlong, utf8, size) != 0) { + + u = 0; + for (i = 0; i < len; i++) { + u = (u << 8) + overlong[i]; + } + + nxt_log_alert(thr->log, + "nxt_utf8_decode(%05uxD, %uz) failed: %05uxD, %uz", + u, len, d, size); + + return NXT_ERROR; + } + } + + return NXT_OK; +} + + +nxt_int_t +nxt_utf8_test(nxt_thread_t *thr) +{ + u_char *p, utf8[4]; + size_t len; + int32_t n; + uint32_t u, d; + nxt_uint_t i, k, l, m; + const u_char *pp; + + nxt_thread_time_update(thr); + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "utf8 test started"); + + /* Test valid UTF-8. */ + + for (u = 0; u < 0x110000; u++) { + + p = nxt_utf8_encode(utf8, u); + + if (p == NULL) { + nxt_log_alert(thr->log, "nxt_utf8_encode(%05uxD) failed", u); + return NXT_ERROR; + } + + pp = utf8; + + d = nxt_utf8_decode(&pp, p); + + if (u != d) { + nxt_log_alert(thr->log, "nxt_utf8_decode(%05uxD) failed: %05uxD", + u, d); + return NXT_ERROR; + } + } + + /* Test some invalid UTF-8. */ + + for (i = 0; i < sizeof(invalid); i += 5) { + + len = invalid[i]; + utf8[0] = invalid[i + 1]; + utf8[1] = invalid[i + 2]; + utf8[2] = invalid[i + 3]; + utf8[3] = invalid[i + 4]; + + pp = utf8; + + d = nxt_utf8_decode(&pp, utf8 + len); + + if (d != 0xffffffff) { + + u = 0; + for (i = 0; i < len; i++) { + u = (u << 8) + utf8[i]; + } + + nxt_log_alert(thr->log, + "nxt_utf8_decode(%05uxD, %uz) failed: %05uxD", + u, len, d); + return NXT_ERROR; + } + } + + /* Test all overlong UTF-8. */ + + for (i = NXT_UTF8_START_TEST; i < 256; i++) { + utf8[0] = i; + + if (nxt_utf8_overlong(thr, utf8, 1) != NXT_OK) { + return NXT_ERROR; + } + + for (k = 0; k < 256; k++) { + utf8[1] = k; + + if (nxt_utf8_overlong(thr, utf8, 2) != NXT_OK) { + return NXT_ERROR; + } + + for (l = 0; l < 256; l++) { + utf8[2] = l; + + if (nxt_utf8_overlong(thr, utf8, 3) != NXT_OK) { + return NXT_ERROR; + } + + for (m = 0; m < 256; m++) { + utf8[3] = m; + + if (nxt_utf8_overlong(thr, utf8, 4) != NXT_OK) { + return NXT_ERROR; + } + } + } + } + } + + n = nxt_utf8_casecmp((u_char *) "ABC АБВ ΑΒΓ", + (u_char *) "abc абв αβγ", + sizeof("ABC АБВ ΑΒΓ") - 1, + sizeof("abc абв αβγ") - 1); + + if (n != 0) { + nxt_log_alert(thr->log, "nxt_utf8_casecmp() failed"); + return NXT_ERROR; + } + + nxt_log_error(NXT_LOG_NOTICE, thr->log, "utf8 test passed"); + return NXT_OK; +} diff --git a/test/nxt_utf8_unit_test.c b/test/nxt_utf8_unit_test.c deleted file mode 100644 index 3bba9681..00000000 --- a/test/nxt_utf8_unit_test.c +++ /dev/null @@ -1,190 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -#define NXT_UTF8_START_TEST 0xc2 -//#define NXT_UTF8_START_TEST 0 - - -static u_char invalid[] = { - - /* Invalid first byte less than 0xc2. */ - 1, 0x80, 0x00, 0x00, 0x00, - 1, 0xc0, 0x00, 0x00, 0x00, - 2, 0xc0, 0x00, 0x00, 0x00, - 3, 0xc0, 0x00, 0x00, 0x00, - 4, 0xc0, 0x00, 0x00, 0x00, - - /* Invalid 0x0x110000 value. */ - 4, 0xf4, 0x90, 0x80, 0x80, - - /* Incomplete length. */ - 2, 0xe0, 0xaf, 0xb5, 0x00, - - /* Overlong values. */ - 2, 0xc0, 0x80, 0x00, 0x00, - 2, 0xc1, 0xb3, 0x00, 0x00, - 3, 0xe0, 0x80, 0x80, 0x00, - 3, 0xe0, 0x81, 0xb3, 0x00, - 3, 0xe0, 0x90, 0x9a, 0x00, - 4, 0xf0, 0x80, 0x8a, 0x80, - 4, 0xf0, 0x80, 0x81, 0xb3, - 4, 0xf0, 0x80, 0xaf, 0xb5, -}; - - -static nxt_int_t -nxt_utf8_overlong(nxt_thread_t *thr, u_char *overlong, size_t len) -{ - u_char *p, utf8[4]; - size_t size; - uint32_t u, d; - nxt_uint_t i; - const u_char *pp; - - pp = overlong; - - d = nxt_utf8_decode(&pp, overlong + len); - - len = pp - overlong; - - if (d != 0xffffffff) { - p = nxt_utf8_encode(utf8, d); - - size = (p != NULL) ? p - utf8 : 0; - - if (len != size || nxt_memcmp(overlong, utf8, size) != 0) { - - u = 0; - for (i = 0; i < len; i++) { - u = (u << 8) + overlong[i]; - } - - nxt_log_alert(thr->log, - "nxt_utf8_decode(%05uxD, %uz) failed: %05uxD, %uz", - u, len, d, size); - - return NXT_ERROR; - } - } - - return NXT_OK; -} - - -nxt_int_t -nxt_utf8_unit_test(nxt_thread_t *thr) -{ - u_char *p, utf8[4]; - size_t len; - int32_t n; - uint32_t u, d; - nxt_uint_t i, k, l, m; - const u_char *pp; - - nxt_thread_time_update(thr); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "utf8 unit test started"); - - /* Test valid UTF-8. */ - - for (u = 0; u < 0x110000; u++) { - - p = nxt_utf8_encode(utf8, u); - - if (p == NULL) { - nxt_log_alert(thr->log, "nxt_utf8_encode(%05uxD) failed", u); - return NXT_ERROR; - } - - pp = utf8; - - d = nxt_utf8_decode(&pp, p); - - if (u != d) { - nxt_log_alert(thr->log, "nxt_utf8_decode(%05uxD) failed: %05uxD", - u, d); - return NXT_ERROR; - } - } - - /* Test some invalid UTF-8. */ - - for (i = 0; i < sizeof(invalid); i += 5) { - - len = invalid[i]; - utf8[0] = invalid[i + 1]; - utf8[1] = invalid[i + 2]; - utf8[2] = invalid[i + 3]; - utf8[3] = invalid[i + 4]; - - pp = utf8; - - d = nxt_utf8_decode(&pp, utf8 + len); - - if (d != 0xffffffff) { - - u = 0; - for (i = 0; i < len; i++) { - u = (u << 8) + utf8[i]; - } - - nxt_log_alert(thr->log, - "nxt_utf8_decode(%05uxD, %uz) failed: %05uxD", - u, len, d); - return NXT_ERROR; - } - } - - /* Test all overlong UTF-8. */ - - for (i = NXT_UTF8_START_TEST; i < 256; i++) { - utf8[0] = i; - - if (nxt_utf8_overlong(thr, utf8, 1) != NXT_OK) { - return NXT_ERROR; - } - - for (k = 0; k < 256; k++) { - utf8[1] = k; - - if (nxt_utf8_overlong(thr, utf8, 2) != NXT_OK) { - return NXT_ERROR; - } - - for (l = 0; l < 256; l++) { - utf8[2] = l; - - if (nxt_utf8_overlong(thr, utf8, 3) != NXT_OK) { - return NXT_ERROR; - } - - for (m = 0; m < 256; m++) { - utf8[3] = m; - - if (nxt_utf8_overlong(thr, utf8, 4) != NXT_OK) { - return NXT_ERROR; - } - } - } - } - } - - n = nxt_utf8_casecmp((u_char *) "ABC АБВ ΑΒΓ", - (u_char *) "abc абв αβγ", - sizeof("ABC АБВ ΑΒΓ") - 1, - sizeof("abc абв αβγ") - 1); - - if (n != 0) { - nxt_log_alert(thr->log, "nxt_utf8_casecmp() failed"); - return NXT_ERROR; - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "utf8 unit test passed"); - return NXT_OK; -} -- cgit