Skip to content

Commit 80e9c83

Browse files
committed
Unify onerror handler used by test framework
1 parent 4521385 commit 80e9c83

10 files changed

+69
-117
lines changed

src/preamble.js

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -305,17 +305,6 @@ assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined'
305305
'JS engine does not provide full typed array support');
306306
#endif
307307

308-
#if IN_TEST_HARNESS
309-
// Test runs in browsers should always be free from uncaught exceptions. If an uncaught exception is thrown, we fail browser test execution in the REPORT_RESULT() macro to output an error value.
310-
if (ENVIRONMENT_IS_WEB) {
311-
window.addEventListener('error', function(e) {
312-
if (e.message.includes('unwind')) return;
313-
console.error('Page threw an exception ' + e);
314-
Module['pageThrewException'] = true;
315-
});
316-
}
317-
#endif
318-
319308
#if IMPORTED_MEMORY
320309
// In non-standalone/normal mode, we create the memory here.
321310
#include "runtime_init_memory.js"

tests/browser/async_bad_list.cpp

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,10 @@
77
#include <emscripten.h>
88

99
int main() {
10-
int x = EM_ASM_INT({
11-
window.onerror = function(e) {
12-
var message = e.toString();
13-
var success = message.indexOf("unreachable") >= 0 || // firefox
14-
message.indexOf("Script error.") >= 0; // chrome
15-
if (success && !Module.reported) {
16-
Module.reported = true;
17-
console.log("reporting success");
18-
// manually REPORT_RESULT; we shouldn't call back into native code at this point
19-
var xhr = new XMLHttpRequest();
20-
xhr.open("GET", "http://localhost:8888/report_result?0");
21-
xhr.onload = xhr.onerror = function() {
22-
window.close();
23-
};
24-
xhr.send();
25-
}
26-
};
27-
return 0;
28-
});
29-
3010
emscripten_sleep(1);
3111

32-
// We should not get here - the unwind will fail as we did now all the right
33-
// functions - this function should be instrumented, but will not be.
12+
// We should not get here - the unwind will fail as we did not list all the
13+
// right functions - this function should be instrumented, but will not be.
3414
puts("We should not get here!");
35-
REPORT_RESULT(1);
36-
37-
return 0;
15+
return 1;
3816
}

tests/browser/async_returnvalue.cpp

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,6 @@ extern "C" int sync_tunnel_bool(bool);
3030
#endif
3131

3232
int main() {
33-
#ifdef BAD
34-
EM_ASM({
35-
window.onerror = function(e) {
36-
var success = e.toString().indexOf("import sync_tunnel was not in ASYNCIFY_IMPORTS, but changed the state") > 0;
37-
if (success && !Module.reported) {
38-
Module.reported = true;
39-
console.log("reporting success");
40-
// manually REPORT_RESULT; we shouldn't call back into native code at this point
41-
var xhr = new XMLHttpRequest();
42-
xhr.open("GET", "http://localhost:8888/report_result?0");
43-
xhr.onload = xhr.onerror = function() {
44-
window.close();
45-
};
46-
xhr.send();
47-
}
48-
};
49-
});
50-
#endif
5133
int x;
5234
x = sync_tunnel(0);
5335
assert(x == 1);
@@ -68,15 +50,13 @@ int main() {
6850
y = sync_tunnel_bool(true);
6951
assert(y == false);
7052

71-
72-
7353
#ifdef BAD
7454
// We should not get here.
7555
printf("We should not get here\n");
56+
return 1;
7657
#else
7758
// Success!
7859
REPORT_RESULT(0);
79-
#endif
80-
8160
return 0;
61+
#endif
8262
}

tests/browser_reporting.js

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
var hasModule = typeof Module === 'object' && Module;
2+
var hasWindow = typeof window === 'object' && window;
3+
var keepWindowAlive = false;
24

35
/** @param {boolean=} sync
46
@param {number=} port */
57
function reportResultToServer(result, sync, port) {
68
port = port || 8888;
79
if (reportResultToServer.reported) {
810
// Only report one result per test, even if the test misbehaves and tries to report more.
9-
reportErrorToServer("excessive reported results, sending " + result + ", test will fail");
11+
reportStderrToServer("excessive reported results, sending " + result + ", test will fail");
1012
}
1113
reportResultToServer.reported = true;
1214
var xhr = new XMLHttpRequest();
13-
if (hasModule && Module['pageThrewException']) {
14-
result = 'pageThrewException';
15-
}
1615
xhr.open('GET', 'http://localhost:' + port + '/report_result?' + result, !sync);
1716
xhr.send();
18-
if (typeof window === 'object' && window && hasModule && !Module['pageThrewException'] /* for easy debugging, don't close window on failure */) setTimeout(function() { window.close() }, 1000);
17+
if (hasWindow && hasModule && !keepWindowAlive) {
18+
setTimeout(function() { window.close() }, 1000);
19+
}
1920
}
2021

2122
/** @param {boolean=} sync
@@ -25,18 +26,29 @@ function maybeReportResultToServer(result, sync, port) {
2526
reportResultToServer(result, sync, port);
2627
}
2728

28-
function reportErrorToServer(message) {
29+
function reportStderrToServer(message) {
2930
var xhr = new XMLHttpRequest();
3031
xhr.open('GET', encodeURI('http://localhost:8888?stderr=' + message));
3132
xhr.send();
3233
}
3334

35+
function reportExceptionToServer(e) {
36+
var xhr = new XMLHttpRequest();
37+
xhr.open('GET', encodeURI('http://localhost:8888?exception=' + e.message + ' / ' + e.stack));
38+
xhr.send();
39+
}
40+
3441
if (typeof window === 'object' && window) {
3542
function report_error(e) {
43+
var message = e.message || e;
44+
// MINIMAL_RUNTIME lets unwind exceptions remain uncaught, and these
45+
// should not be considered actually errors.
46+
if (message == 'unwind') {
47+
return;
48+
}
49+
console.error("emtest: got top level error: " + message);
3650
// MINIMAL_RUNTIME doesn't handle exit or call the below onExit handler
3751
// so we detect the exit by parsing the uncaught exception message.
38-
var message = e.message || e;
39-
console.error("got top level error: " + message);
4052
var offset = message.indexOf('exit(');
4153
if (offset != -1) {
4254
var status = message.substring(offset + 5);
@@ -45,9 +57,14 @@ if (typeof window === 'object' && window) {
4557
console.error(status);
4658
maybeReportResultToServer('exit:' + status);
4759
} else {
48-
var xhr = new XMLHttpRequest();
49-
xhr.open('GET', encodeURI('http://localhost:8888?exception=' + e.message + ' / ' + e.stack));
50-
xhr.send();
60+
reportExceptionToServer(e);
61+
/*
62+
* Also report the exception as the result of the test if non has been
63+
* reported yet
64+
* For easy debugging, don't close window on failure.
65+
*/
66+
keepWindowAlive = true;
67+
maybeReportResultToServer('exception:' + e.message);
5168
}
5269
}
5370
window.addEventListener('error', report_error);

tests/common.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,7 +1344,7 @@ def assert_out_queue_empty(self, who):
13441344
# synchronously, so we have a timeout, which can be hit if the VM
13451345
# we run on stalls temporarily), so we let each test try more than
13461346
# once by default
1347-
def run_browser(self, html_file, message, expectedResult=None, timeout=None, extra_tries=1):
1347+
def run_browser(self, html_file, message, expectedResult=None, timeout=None, extra_tries=1, assert_all=False):
13481348
if not has_browser():
13491349
return
13501350
if BrowserCore.unresponsive_tests >= BrowserCore.MAX_UNRESPONSIVE_TESTS:
@@ -1382,12 +1382,16 @@ def run_browser(self, html_file, message, expectedResult=None, timeout=None, ext
13821382
# verify the result, and try again if we should do so
13831383
output = unquote(output)
13841384
try:
1385-
self.assertContained(expectedResult, output)
1385+
if assert_all:
1386+
for o in expectedResult:
1387+
self.assertContained(o, output)
1388+
else:
1389+
self.assertContained(expectedResult, output)
13861390
except Exception as e:
13871391
if extra_tries > 0:
13881392
print('[test error (see below), automatically retrying]')
13891393
print(e)
1390-
return self.run_browser(html_file, message, expectedResult, timeout, extra_tries - 1)
1394+
return self.run_browser(html_file, message, expectedResult, timeout, extra_tries - 1, assert_all=assert_all)
13911395
else:
13921396
raise e
13931397
finally:

tests/emscripten_throw_number.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,5 @@
33
int main()
44
{
55
emscripten_throw_number(42);
6-
#ifdef REPORT_RESULT
7-
REPORT_RESULT(1); // failed
8-
#endif
6+
__builtin_trap();
97
}

tests/emscripten_throw_number_pre.js

Lines changed: 0 additions & 8 deletions
This file was deleted.

tests/emscripten_throw_string.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,5 @@
33
int main()
44
{
55
emscripten_throw_string("Hello!");
6-
#ifdef REPORT_RESULT
7-
REPORT_RESULT(1); // failed
8-
#endif
6+
__builtin_trap();
97
}

tests/emscripten_throw_string_pre.js

Lines changed: 0 additions & 8 deletions
This file was deleted.

tests/test_browser.py

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -627,14 +627,6 @@ def setup(assetLocalization):
627627
<center><canvas id='canvas' width='256' height='256'></canvas></center>
628628
<hr><div id='output'></div><hr>
629629
<script type='text/javascript'>
630-
window.onerror = function(error) {
631-
window.onerror = null;
632-
var result = error.indexOf("test.data") >= 0 ? 1 : 0;
633-
var xhr = new XMLHttpRequest();
634-
xhr.open('GET', 'http://localhost:8888/report_result?' + result, true);
635-
xhr.send();
636-
setTimeout(function() { window.close() }, 1000);
637-
}
638630
var Module = {
639631
locateFile: function (path, prefix) {if (path.endsWith(".wasm")) {return prefix + path;} else {return "''' + assetLocalization + r'''" + path;}},
640632
print: (function() {
@@ -653,17 +645,17 @@ def test():
653645
setup("")
654646
self.compile_btest(['main.cpp', '--shell-file', 'on_window_error_shell.html', '--preload-file', 'data.txt', '-o', 'test.html'])
655647
shutil.move('test.data', 'missing.data')
656-
self.run_browser('test.html', '', '/report_result?1')
648+
self.run_browser('test.html', '', ['/report_result?exception:', 'test.data'], assert_all=True)
657649

658650
# test unknown protocol should go through xhr.onerror
659651
setup("unknown_protocol://")
660652
self.compile_btest(['main.cpp', '--shell-file', 'on_window_error_shell.html', '--preload-file', 'data.txt', '-o', 'test.html'])
661-
self.run_browser('test.html', '', '/report_result?1')
653+
self.run_browser('test.html', '', ['/report_result?exception:', 'test.data'], assert_all=True)
662654

663655
# test wrong protocol and port
664656
setup("https://localhost:8800/")
665657
self.compile_btest(['main.cpp', '--shell-file', 'on_window_error_shell.html', '--preload-file', 'data.txt', '-o', 'test.html'])
666-
self.run_browser('test.html', '', '/report_result?1')
658+
self.run_browser('test.html', '', ['/report_result?exception:', 'test.data'], assert_all=True)
667659

668660
test()
669661

@@ -3316,22 +3308,33 @@ def test_async_iostream(self):
33163308
# ASYNCIFY_IMPORTS.
33173309
# To make the test more precise we also use ASYNCIFY_IGNORE_INDIRECT here.
33183310
@parameterized({
3319-
'normal': (['-s', 'ASYNCIFY_IMPORTS=[sync_tunnel, sync_tunnel_bool]'],), # noqa
3320-
'response': (['-s', '[email protected]'],), # noqa
3321-
'nothing': (['-DBAD'],), # noqa
3322-
'empty_list': (['-DBAD', '-s', 'ASYNCIFY_IMPORTS=[]'],), # noqa
3323-
'em_js_bad': (['-DBAD', '-DUSE_EM_JS'],), # noqa
3311+
'normal': (False, ['-s', 'ASYNCIFY_IMPORTS=[sync_tunnel, sync_tunnel_bool]'],), # noqa
3312+
'response': (False, ['-s', '[email protected]'],), # noqa
3313+
'nothing': (True, ['-DBAD'],), # noqa
3314+
'empty_list': (True, ['-DBAD', '-s', 'ASYNCIFY_IMPORTS=[]'],), # noqa
3315+
'em_js_bad': (True, ['-DBAD', '-DUSE_EM_JS'],), # noqa
33243316
})
3325-
def test_async_returnvalue(self, args):
3317+
def test_async_returnvalue(self, bad, args):
3318+
if bad:
3319+
expected = [
3320+
'exception:Uncaught Error: import sync_tunnel was not in ASYNCIFY_IMPORTS, but changed the state', # firefox
3321+
'exception:Error: import sync_tunnel was not in ASYNCIFY_IMPORTS, but changed the state' # chrome
3322+
]
3323+
else:
3324+
expected = "0"
33263325
if '@' in str(args):
33273326
create_file('filey.txt', 'sync_tunnel\nsync_tunnel_bool\n')
3328-
self.btest('browser/async_returnvalue.cpp', '0', args=['-s', 'ASYNCIFY', '-s', 'ASYNCIFY_IGNORE_INDIRECT', '--js-library', test_file('browser/async_returnvalue.js')] + args + ['-s', 'ASSERTIONS'])
3327+
self.btest('browser/async_returnvalue.cpp', expected, args=['-s', 'ASYNCIFY', '-s', 'ASYNCIFY_IGNORE_INDIRECT', '--js-library', test_file('browser/async_returnvalue.js')] + args + ['-s', 'ASSERTIONS'])
33293328

33303329
def test_async_stack_overflow(self):
33313330
self.btest('browser/async_stack_overflow.cpp', 'abort:RuntimeError: unreachable', args=['-s', 'ASYNCIFY', '-s', 'ASYNCIFY_STACK_SIZE=4'])
33323331

33333332
def test_async_bad_list(self):
3334-
self.btest('browser/async_bad_list.cpp', '0', args=['-s', 'ASYNCIFY', '-s', 'ASYNCIFY_ONLY=[waka]', '--profiling'])
3333+
expected = [
3334+
'exception:RuntimeError: unreachable executed', # firefox
3335+
'exception:Uncaught RuntimeError: unreachable', # chrome
3336+
]
3337+
self.btest('browser/async_bad_list.cpp', expected, args=['-s', 'ASYNCIFY', '-s', 'ASYNCIFY_ONLY=[waka]', '--profiling'])
33353338

33363339
# Tests that when building with -s MINIMAL_RUNTIME=1, the build can use -s MODULARIZE=1 as well.
33373340
def test_minimal_runtime_modularize(self):
@@ -4298,8 +4301,9 @@ def test_small_js_flags(self):
42984301
# Check an absolute js code size, with some slack.
42994302
size = os.path.getsize('test.js')
43004303
print('size:', size)
4301-
# Note that this size includes test harness additions (for reporting the result, etc.).
4302-
self.assertLess(abs(size - 5629), 100)
4304+
# Note that this size includes test harness additions (so will change when, for example,
4305+
# browser_reporting.js changed)
4306+
self.assertLess(abs(size - 5496), 100)
43034307

43044308
# Tests that it is possible to initialize and render WebGL content in a pthread by using OffscreenCanvas.
43054309
# -DTEST_CHAINED_WEBGL_CONTEXT_PASSING: Tests that it is possible to transfer WebGL canvas in a chain from main thread -> thread 1 -> thread 2 and then init and render WebGL content there.
@@ -4978,10 +4982,10 @@ def test_emscripten_console_log(self):
49784982
self.btest(test_file('emscripten_console_log.c'), '0', args=['--pre-js', test_file('emscripten_console_log_pre.js')])
49794983

49804984
def test_emscripten_throw_number(self):
4981-
self.btest(test_file('emscripten_throw_number.c'), '0', args=['--pre-js', test_file('emscripten_throw_number_pre.js')])
4985+
self.btest(test_file('emscripten_throw_number.c'), 'exception:Uncaught 42')
49824986

49834987
def test_emscripten_throw_string(self):
4984-
self.btest(test_file('emscripten_throw_string.c'), '0', args=['--pre-js', test_file('emscripten_throw_string_pre.js')])
4988+
self.btest(test_file('emscripten_throw_string.c'), 'exception:Uncaught Hello!')
49854989

49864990
# Tests that Closure run in combination with -s ENVIRONMENT=web mode works with a minimal console.log() application
49874991
def test_closure_in_web_only_target_environment_console_log(self):

0 commit comments

Comments
 (0)