Enable browser tests to be run under node In some cases, specifically thread tests, it can be useful to expriment with running browser tests under node. This change add a new special value to EMTEST_BROSWER that will cause `btest` to attempt to run the test under node. I've also adding since browser test to the wasm2-test suite in circle CI so this features gets tested.
diff --git a/.circleci/config.yml b/.circleci/config.yml index 1a0a621..cbbbb6c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml
@@ -364,10 +364,12 @@ test_targets: "wasm0" test-wasm2: executor: bionic + environment: + EMTEST_BROWSER: "node" steps: - run-tests: - # also add a few asan tests - test_targets: "wasm2 asan.test_embind* asan.test_abort_on_exceptions asan.test_ubsan_full_left_shift_fsanitize_integer asan.test_pthread* asan.test_dyncall_specific_minimal_runtime" + # also add a few asan tests and a single test of EMTEST_BROWSER=node + test_targets: "wasm2 asan.test_embind* asan.test_abort_on_exceptions asan.test_ubsan_full_left_shift_fsanitize_integer asan.test_pthread* asan.test_dyncall_specific_minimal_runtime browser.test_pthread_join" test-wasm3: executor: bionic steps:
diff --git a/tests/browser_reporting.js b/tests/browser_reporting.js index 125fa9e..6c3c1c9 100644 --- a/tests/browser_reporting.js +++ b/tests/browser_reporting.js
@@ -9,13 +9,20 @@ reportErrorToServer("excessive reported results, sending " + result + ", test will fail"); } reportResultToServer.reported = true; - var xhr = new XMLHttpRequest(); - if (hasModule && Module['pageThrewException']) { - result = 'pageThrewException'; + if (ENVIRONMENT_IS_NODE) { + out('RESULT: ' + result); + } else { + var xhr = new XMLHttpRequest(); + if (hasModule && Module['pageThrewException']) { + result = 'pageThrewException'; + } + xhr.open('GET', 'http://localhost:' + port + '/report_result?' + result, !sync); + xhr.send(); + /* for easy debugging, don't close window on failure */ + if (typeof window === 'object' && window && hasModule && !Module['pageThrewException']) { + setTimeout(function() { window.close() }, 1000); + } } - xhr.open('GET', 'http://localhost:' + port + '/report_result?' + result, !sync); - xhr.send(); - if (typeof window === 'object' && window && hasModule && !Module['pageThrewException'] /* for easy debugging, don't close window on failure */) setTimeout(function() { window.close() }, 1000); } /** @param {boolean=} sync @@ -27,8 +34,12 @@ function reportErrorToServer(message) { var xhr = new XMLHttpRequest(); - xhr.open('GET', encodeURI('http://localhost:8888?stderr=' + message)); - xhr.send(); + if (ENVIRONMENT_IS_NODE) { + err(message); + } else { + xhr.open('GET', encodeURI('http://localhost:8888?stderr=' + message)); + xhr.send(); + } } if (typeof window === 'object' && window) {
diff --git a/tests/common.py b/tests/common.py index b0a45cc..1688236 100644 --- a/tests/common.py +++ b/tests/common.py
@@ -40,8 +40,14 @@ # User can specify an environment variable EMTEST_BROWSER to force the browser # test suite to run using another browser command line than the default system -# browser. Setting '0' as the browser disables running a browser (but we still -# see tests compile) +# browser. +# There are two special value that can be used here if running in an actual +# browser is not desired: +# EMTEST_BROWSER=0 : This will disable the actual running of the test and simply +# verify that it compiles and links. +# EMTEST_BROWSER=node : This will attempt to run the browser test under node. +# For most browser tests this does not work, but it can +# be useful for running pthread tests under node. EMTEST_BROWSER = None EMTEST_DETECT_TEMPFILE_LEAKS = None EMTEST_SAVE_DIR = None @@ -1299,7 +1305,7 @@ super().setUpClass() cls.also_asmjs = int(os.getenv('EMTEST_BROWSER_ALSO_ASMJS', '0')) == 1 cls.port = int(os.getenv('EMTEST_BROWSER_PORT', '8888')) - if not has_browser(): + if not has_browser() or EMTEST_BROWSER == 'node': return cls.browser_timeout = 60 cls.harness_in_queue = multiprocessing.Queue() @@ -1312,7 +1318,7 @@ @classmethod def tearDownClass(cls): super().tearDownClass() - if not has_browser(): + if not has_browser() or EMTEST_BROWSER == 'node': return cls.harness_server.terminate() print('[Browser harness server terminated]') @@ -1512,6 +1518,8 @@ args += ['-I' + TEST_ROOT, '-include', test_file('report_result.h'), test_file('report_result.cpp')] + if EMTEST_BROWSER == 'node': + args.append('-DEMTEST_NODE') self.run_process([EMCC] + self.get_emcc_args() + args) def btest_exit(self, filename, assert_returncode=0, *args, **kwargs): @@ -1554,7 +1562,13 @@ post_build() if not isinstance(expected, list): expected = [expected] - self.run_browser(outfile + url_suffix, message, ['/report_result?' + e for e in expected], timeout=timeout, extra_tries=extra_tries) + if EMTEST_BROWSER == 'node': + self.js_engines = [config.NODE_JS] + self.node_args += ['--experimental-wasm-threads', '--experimental-wasm-bulk-memory'] + output = self.run_js('test.js') + self.assertContained('RESULT: ' + expected[0], output) + else: + self.run_browser(outfile + url_suffix, message, ['/report_result?' + e for e in expected], timeout=timeout, extra_tries=extra_tries) # Tests can opt into being run under asmjs as well if 'WASM=0' not in original_args and (also_asmjs or self.also_asmjs):
diff --git a/tests/pthread/test_pthread_create.cpp b/tests/pthread/test_pthread_create.cpp index 901f6c8..ff89809 100644 --- a/tests/pthread/test_pthread_create.cpp +++ b/tests/pthread/test_pthread_create.cpp
@@ -81,8 +81,8 @@ CreateThread(i); // Join all threads and create more. - while (numThreadsToCreate > 0) - { + while (numThreadsToCreate > 0) + { for(int i = 0; i < NUM_THREADS; ++i) { if (thread[i]) @@ -101,5 +101,6 @@ } } } + printf("All threads joined.\n"); return 0; }
diff --git a/tests/report_result.cpp b/tests/report_result.cpp index 630c5c5..fe1ff61 100644 --- a/tests/report_result.cpp +++ b/tests/report_result.cpp
@@ -6,35 +6,55 @@ */ #include <stdio.h> +#include <stdlib.h> -#ifdef __EMSCRIPTEN__ +#include "report_result.h" +#if defined __EMSCRIPTEN__ && !defined EMTEST_NODE #include <emscripten.h> - -#ifndef EMTEST_PORT_NUMBER -#error "EMTEST_PORT_NUMBER not defined" #endif #ifdef __cplusplus extern "C" { #endif -void EMSCRIPTEN_KEEPALIVE _ReportResult(int result, int sync) -{ +#if defined __EMSCRIPTEN__ && !defined EMTEST_NODE +#ifndef EMTEST_PORT_NUMBER +#error "EMTEST_PORT_NUMBER not defined" +#endif + +void EMSCRIPTEN_KEEPALIVE _ReportResult(int result, int sync) { EM_ASM({ reportResultToServer($0, $1, $2); }, result, sync, EMTEST_PORT_NUMBER); } -void EMSCRIPTEN_KEEPALIVE _MaybeReportResult(int result, int sync) -{ +void EMSCRIPTEN_KEEPALIVE _MaybeReportResult(int result, int sync) { EM_ASM({ maybeReportResultToServer($0, $1, $2); }, result, sync, EMTEST_PORT_NUMBER); } +#else + +static bool reported = false; + +void _ReportResult(int result, int sync) { + if (reported) { + printf("ERROR: result already reported\n"); + exit(1); + } + reported = true; + printf("RESULT: %d\n", result); +} + +void _MaybeReportResult(int result, int sync) { + if (!reported) _ReportResult(result, sync); +} + +#endif // __EMSCRIPTEN__ && !defined EMTEST_NODE + #ifdef __cplusplus } #endif -#endif // __EMSCRIPTEN__
diff --git a/tests/report_result.h b/tests/report_result.h index 2012bdf..cd0ceca 100644 --- a/tests/report_result.h +++ b/tests/report_result.h
@@ -10,8 +10,6 @@ #ifndef REPORT_RESULT_H_ #define REPORT_RESULT_H_ -#ifdef __EMSCRIPTEN__ - #ifdef __cplusplus extern "C" { #endif @@ -23,7 +21,8 @@ } #endif -#if __EMSCRIPTEN_PTHREADS__ +#if defined __EMSCRIPTEN__ && defined __EMSCRIPTEN_PTHREADS__ + #include <emscripten.h> #include <emscripten/threading.h> #define REPORT_RESULT(result) emscripten_async_run_in_main_runtime_thread(EM_FUNC_SIG_VII, _ReportResult, (result), 0) #define REPORT_RESULT_SYNC(result) emscripten_sync_run_in_main_runtime_thread(EM_FUNC_SIG_VII, _ReportResult, (result), 1) @@ -36,19 +35,4 @@ #define MAYBE_REPORT_RESULT_SYNC(result) _MaybeReportResult((result), 1) #endif -#else - -#include <stdio.h> -#include <stdlib.h> - -#define REPORT_RESULT(result) \ - do { \ - printf("result: %d\n", result); \ - exit(result); \ - } - -#define REPORT_RESULT_SYNC REPORT_RESULT - -#endif // __EMSCRIPTEN__ - #endif // REPORT_RESULT_H_
diff --git a/tests/sdl2_net_client.c b/tests/sdl2_net_client.c index 90293ca..4610814 100644 --- a/tests/sdl2_net_client.c +++ b/tests/sdl2_net_client.c
@@ -24,7 +24,7 @@ #include "SDL_net.h" #ifdef __EMSCRIPTEN__ -#include <emscripten.h> +#include <emscripten/emscripten.h> #endif typedef enum {
diff --git a/tests/test_browser.py b/tests/test_browser.py index 9a4c4d8..c6465d6 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py
@@ -160,9 +160,10 @@ def setUpClass(cls): super().setUpClass() cls.browser_timeout = 60 - print() - print('Running the browser tests. Make sure the browser allows popups from localhost.') - print() + if EMTEST_BROWSER != 'node': + print() + print('Running the browser tests. Make sure the browser allows popups from localhost.') + print() def setUp(self): super().setUp()