Skip to content

Commit 96b344c

Browse files
tiranbrettcannon
andauthoredFeb 5, 2022
bpo-40280: Address more test failures on Emscripten (GH-31050)
Co-authored-by: Brett Cannon <brett@python.org>
1 parent 9d4161a commit 96b344c

27 files changed

+228
-50
lines changed
 

‎Lib/test/support/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,8 @@ def reap_children():
12781278
# Need os.waitpid(-1, os.WNOHANG): Windows is not supported
12791279
if not (hasattr(os, 'waitpid') and hasattr(os, 'WNOHANG')):
12801280
return
1281+
elif not has_subprocess_support:
1282+
return
12811283

12821284
# Reap all our dead child processes so we don't leave zombies around.
12831285
# These hog resources and might be causing some of the buildbots to die.

‎Lib/test/support/os_helper.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ def __fspath__(self):
502502
def fd_count():
503503
"""Count the number of open file descriptors.
504504
"""
505-
if sys.platform.startswith(('linux', 'freebsd')):
505+
if sys.platform.startswith(('linux', 'freebsd', 'emscripten')):
506506
try:
507507
names = os.listdir("/proc/self/fd")
508508
# Subtract one because listdir() internally opens a file

‎Lib/test/test_builtin.py

+2
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ def test_compile_top_level_await_no_coro(self):
393393
msg=f"source={source} mode={mode}")
394394

395395

396+
@unittest.skipIf(support.is_emscripten, "socket.accept is broken")
396397
def test_compile_top_level_await(self):
397398
"""Test whether code some top level await can be compiled.
398399
@@ -1213,6 +1214,7 @@ def test_open_default_encoding(self):
12131214
os.environ.clear()
12141215
os.environ.update(old_environ)
12151216

1217+
@support.requires_subprocess()
12161218
def test_open_non_inheritable(self):
12171219
fileobj = open(__file__, encoding="utf-8")
12181220
with fileobj:

‎Lib/test/test_capi.py

+2
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,7 @@ def check_fatal_error(self, code, expected, not_expected=()):
611611
self.assertNotIn(name, modules)
612612
self.assertEqual(len(modules), total)
613613

614+
@support.requires_subprocess()
614615
def test_fatal_error(self):
615616
# By default, stdlib extension modules are ignored,
616617
# but not test modules.
@@ -880,6 +881,7 @@ class Test_testinternalcapi(unittest.TestCase):
880881
if name.startswith('test_'))
881882

882883

884+
@support.requires_subprocess()
883885
class PyMemDebugTests(unittest.TestCase):
884886
PYTHONMALLOC = 'debug'
885887
# '0x04c06e0' or '04C06E0'

‎Lib/test/test_faulthandler.py

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
except ImportError:
2020
_testcapi = None
2121

22+
if not support.has_subprocess_support:
23+
raise unittest.SkipTest("test module requires subprocess")
24+
2225
TIMEOUT = 0.5
2326
MS_WINDOWS = (os.name == 'nt')
2427

‎Lib/test/test_fileio.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from weakref import proxy
1010
from functools import wraps
1111

12-
from test.support import cpython_only, swap_attr, gc_collect
12+
from test.support import cpython_only, swap_attr, gc_collect, is_emscripten
1313
from test.support.os_helper import (TESTFN, TESTFN_UNICODE, make_bad_fd)
1414
from test.support.warnings_helper import check_warnings
1515
from collections import UserList
@@ -373,7 +373,7 @@ def testAbles(self):
373373
self.assertEqual(f.isatty(), False)
374374
f.close()
375375

376-
if sys.platform != "win32":
376+
if sys.platform != "win32" and not is_emscripten:
377377
try:
378378
f = self.FileIO("/dev/tty", "a")
379379
except OSError:

‎Lib/test/test_genericalias.py

+12-5
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,20 @@
2424
from fileinput import FileInput
2525
from itertools import chain
2626
from http.cookies import Morsel
27-
from multiprocessing.managers import ValueProxy
28-
from multiprocessing.pool import ApplyResult
27+
try:
28+
from multiprocessing.managers import ValueProxy
29+
from multiprocessing.pool import ApplyResult
30+
from multiprocessing.queues import SimpleQueue as MPSimpleQueue
31+
except ImportError:
32+
# _multiprocessing module is optional
33+
ValueProxy = None
34+
ApplyResult = None
35+
MPSimpleQueue = None
2936
try:
3037
from multiprocessing.shared_memory import ShareableList
3138
except ImportError:
3239
# multiprocessing.shared_memory is not available on e.g. Android
3340
ShareableList = None
34-
from multiprocessing.queues import SimpleQueue as MPSimpleQueue
3541
from os import DirEntry
3642
from re import Pattern, Match
3743
from types import GenericAlias, MappingProxyType, AsyncGeneratorType
@@ -79,13 +85,14 @@ class BaseTest(unittest.TestCase):
7985
Queue, SimpleQueue,
8086
_AssertRaisesContext,
8187
SplitResult, ParseResult,
82-
ValueProxy, ApplyResult,
8388
WeakSet, ReferenceType, ref,
84-
ShareableList, MPSimpleQueue,
89+
ShareableList,
8590
Future, _WorkItem,
8691
Morsel]
8792
if ctypes is not None:
8893
generic_types.extend((ctypes.Array, ctypes.LibraryLoader))
94+
if ValueProxy is not None:
95+
generic_types.extend((ValueProxy, ApplyResult, MPSimpleQueue))
8996

9097
def test_subscriptable(self):
9198
for t in self.generic_types:

‎Lib/test/test_getpass.py

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ def test_username_priorities_of_env_values(self, environ):
2828
getpass.getuser()
2929
except ImportError: # in case there's no pwd module
3030
pass
31+
except KeyError:
32+
# current user has no pwd entry
33+
pass
3134
self.assertEqual(
3235
environ.get.call_args_list,
3336
[mock.call(x) for x in ('LOGNAME', 'USER', 'LNAME', 'USERNAME')])

‎Lib/test/test_inspect.py

+1
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,7 @@ def test_nested_class_definition_inside_function(self):
788788
self.assertSourceEqual(mod2.cls213, 218, 222)
789789
self.assertSourceEqual(mod2.cls213().func219(), 220, 221)
790790

791+
@unittest.skipIf(support.is_emscripten, "socket.accept is broken")
791792
def test_nested_class_definition_inside_async_function(self):
792793
import asyncio
793794
self.addCleanup(asyncio.set_event_loop_policy, None)

‎Lib/test/test_interpreters.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
import unittest
66
import time
77

8-
import _xxsubinterpreters as _interpreters
8+
from test.support import import_helper
9+
_interpreters = import_helper.import_module('_xxsubinterpreters')
910
from test.support import interpreters
1011

1112

‎Lib/test/test_io.py

+13
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ def _default_chunk_size():
7676
with open(__file__, "r", encoding="latin-1") as f:
7777
return f._CHUNK_SIZE
7878

79+
requires_alarm = unittest.skipUnless(
80+
hasattr(signal, "alarm"), "test requires signal.alarm()"
81+
)
82+
7983

8084
class MockRawIOWithoutRead:
8185
"""A RawIO implementation without read(), so as to exercise the default
@@ -4435,12 +4439,15 @@ def _read():
44354439
if e.errno != errno.EBADF:
44364440
raise
44374441

4442+
@requires_alarm
44384443
def test_interrupted_write_unbuffered(self):
44394444
self.check_interrupted_write(b"xy", b"xy", mode="wb", buffering=0)
44404445

4446+
@requires_alarm
44414447
def test_interrupted_write_buffered(self):
44424448
self.check_interrupted_write(b"xy", b"xy", mode="wb")
44434449

4450+
@requires_alarm
44444451
def test_interrupted_write_text(self):
44454452
self.check_interrupted_write("xy", b"xy", mode="w", encoding="ascii")
44464453

@@ -4472,9 +4479,11 @@ def on_alarm(*args):
44724479
wio.close()
44734480
os.close(r)
44744481

4482+
@requires_alarm
44754483
def test_reentrant_write_buffered(self):
44764484
self.check_reentrant_write(b"xy", mode="wb")
44774485

4486+
@requires_alarm
44784487
def test_reentrant_write_text(self):
44794488
self.check_reentrant_write("xy", mode="w", encoding="ascii")
44804489

@@ -4502,10 +4511,12 @@ def alarm_handler(sig, frame):
45024511
os.close(w)
45034512
os.close(r)
45044513

4514+
@requires_alarm
45054515
def test_interrupted_read_retry_buffered(self):
45064516
self.check_interrupted_read_retry(lambda x: x.decode('latin1'),
45074517
mode="rb")
45084518

4519+
@requires_alarm
45094520
def test_interrupted_read_retry_text(self):
45104521
self.check_interrupted_read_retry(lambda x: x,
45114522
mode="r", encoding="latin1")
@@ -4578,9 +4589,11 @@ def alarm2(sig, frame):
45784589
if e.errno != errno.EBADF:
45794590
raise
45804591

4592+
@requires_alarm
45814593
def test_interrupted_write_retry_buffered(self):
45824594
self.check_interrupted_write_retry(b"x", mode="wb")
45834595

4596+
@requires_alarm
45844597
def test_interrupted_write_retry_text(self):
45854598
self.check_interrupted_write_retry("x", mode="w", encoding="latin1")
45864599

‎Lib/test/test_os.py

+4
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,7 @@ def _empty_mapping(self):
992992
@unittest.skipUnless(unix_shell and os.path.exists(unix_shell),
993993
'requires a shell')
994994
@unittest.skipUnless(hasattr(os, 'popen'), "needs os.popen()")
995+
@support.requires_subprocess()
995996
def test_update2(self):
996997
os.environ.clear()
997998
os.environ.update(HELLO="World")
@@ -1002,6 +1003,7 @@ def test_update2(self):
10021003
@unittest.skipUnless(unix_shell and os.path.exists(unix_shell),
10031004
'requires a shell')
10041005
@unittest.skipUnless(hasattr(os, 'popen'), "needs os.popen()")
1006+
@support.requires_subprocess()
10051007
def test_os_popen_iter(self):
10061008
with os.popen("%s -c 'echo \"line1\nline2\nline3\"'"
10071009
% unix_shell) as popen:
@@ -1173,6 +1175,8 @@ def test_iter_error_when_changing_os_environ_values(self):
11731175
def _test_underlying_process_env(self, var, expected):
11741176
if not (unix_shell and os.path.exists(unix_shell)):
11751177
return
1178+
elif not support.has_subprocess_support:
1179+
return
11761180

11771181
with os.popen(f"{unix_shell} -c 'echo ${var}'") as popen:
11781182
value = popen.read().strip()

‎Lib/test/test_posix.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ def test_truncate(self):
184184
posix.truncate(os_helper.TESTFN, 0)
185185

186186
@unittest.skipUnless(getattr(os, 'execve', None) in os.supports_fd, "test needs execve() to support the fd parameter")
187-
@unittest.skipUnless(hasattr(os, 'fork'), "test needs os.fork()")
187+
@support.requires_fork()
188188
def test_fexecve(self):
189189
fp = os.open(sys.executable, os.O_RDONLY)
190190
try:
@@ -199,7 +199,7 @@ def test_fexecve(self):
199199

200200

201201
@unittest.skipUnless(hasattr(posix, 'waitid'), "test needs posix.waitid()")
202-
@unittest.skipUnless(hasattr(os, 'fork'), "test needs os.fork()")
202+
@support.requires_fork()
203203
def test_waitid(self):
204204
pid = os.fork()
205205
if pid == 0:
@@ -209,7 +209,7 @@ def test_waitid(self):
209209
res = posix.waitid(posix.P_PID, pid, posix.WEXITED)
210210
self.assertEqual(pid, res.si_pid)
211211

212-
@unittest.skipUnless(hasattr(os, 'fork'), "test needs os.fork()")
212+
@support.requires_fork()
213213
def test_register_at_fork(self):
214214
with self.assertRaises(TypeError, msg="Positional args not allowed"):
215215
os.register_at_fork(lambda: None)
@@ -1056,6 +1056,7 @@ def test_getgrouplist(self):
10561056

10571057
@unittest.skipUnless(hasattr(os, 'getegid'), "test needs os.getegid()")
10581058
@unittest.skipUnless(hasattr(os, 'popen'), "test needs os.popen()")
1059+
@support.requires_subprocess()
10591060
def test_getgroups(self):
10601061
with os.popen('id -G 2>/dev/null') as idg:
10611062
groups = idg.read().strip()
@@ -1481,7 +1482,7 @@ def test_unlink_dir_fd(self):
14811482
self.addCleanup(posix.unlink, fullname)
14821483
raise
14831484

1484-
@unittest.skipUnless(os.mkfifo in os.supports_dir_fd, "test needs dir_fd support in os.mkfifo()")
1485+
@unittest.skipUnless(hasattr(os, 'mkfifo') and os.mkfifo in os.supports_dir_fd, "test needs dir_fd support in os.mkfifo()")
14851486
def test_mkfifo_dir_fd(self):
14861487
with self.prepare() as (dir_fd, name, fullname):
14871488
try:

‎Lib/test/test_pwd.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def test_errors(self):
6969

7070
allnames = list(bynames.keys())
7171
namei = 0
72-
fakename = allnames[namei]
72+
fakename = allnames[namei] if allnames else "invaliduser"
7373
while fakename in bynames:
7474
chars = list(fakename)
7575
for i in range(len(chars)):

‎Lib/test/test_pyexpat.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from xml.parsers import expat
1313
from xml.parsers.expat import errors
1414

15-
from test.support import sortdict
15+
from test.support import sortdict, is_emscripten
1616

1717

1818
class SetAttributeTest(unittest.TestCase):
@@ -466,7 +466,10 @@ def test_exception(self):
466466
"pyexpat.c", "StartElement")
467467
self.check_traceback_entry(entries[2],
468468
"test_pyexpat.py", "StartElementHandler")
469-
if sysconfig.is_python_build() and not (sys.platform == 'win32' and platform.machine() == 'ARM'):
469+
if (sysconfig.is_python_build()
470+
and not (sys.platform == 'win32' and platform.machine() == 'ARM')
471+
and not is_emscripten
472+
):
470473
self.assertIn('call_with_frame("StartElement"', entries[1][3])
471474

472475

‎Lib/test/test_resource.py

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ def test_fsize_toobig(self):
9898
except (OverflowError, ValueError):
9999
pass
100100

101+
@unittest.skipUnless(hasattr(resource, "getrusage"), "needs getrusage")
101102
def test_getrusage(self):
102103
self.assertRaises(TypeError, resource.getrusage)
103104
self.assertRaises(TypeError, resource.getrusage, 42, 42)

‎Lib/test/test_zipfile.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
from test.support import script_helper
2323
from test.support import (findfile, requires_zlib, requires_bz2,
2424
requires_lzma, captured_stdout, requires_subprocess)
25-
from test.support.os_helper import TESTFN, unlink, rmtree, temp_dir, temp_cwd
25+
from test.support.os_helper import (
26+
TESTFN, unlink, rmtree, temp_dir, temp_cwd, fd_count
27+
)
2628

2729

2830
TESTFN2 = TESTFN + "2"
@@ -2539,14 +2541,14 @@ def test_write_after_read(self):
25392541
def test_many_opens(self):
25402542
# Verify that read() and open() promptly close the file descriptor,
25412543
# and don't rely on the garbage collector to free resources.
2544+
startcount = fd_count()
25422545
self.make_test_archive(TESTFN2)
25432546
with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
25442547
for x in range(100):
25452548
zipf.read('ones')
25462549
with zipf.open('ones') as zopen1:
25472550
pass
2548-
with open(os.devnull, "rb") as f:
2549-
self.assertLess(f.fileno(), 100)
2551+
self.assertEqual(startcount, fd_count())
25502552

25512553
def test_write_while_reading(self):
25522554
with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_DEFLATED) as zipf:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Fix wasm32-emscripten test failures and platform issues.
2+
- Disable syscalls that are not supported or don't work, e.g.
3+
wait, getrusage, prlimit, mkfifo, mknod, setres[gu]id, setgroups.
4+
- Use fd_count to cound open fds.
5+
- Add more checks for subprocess and fork.
6+
- Add workarounds for missing _multiprocessing and failing socket.accept().
7+
- Enable bzip2.
8+
- Disable large file support.
9+
- Disable signal.alarm.

‎Modules/clinic/resource.c.h

+9-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
Please sign in to comment.