Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-40280: Address more test failures on Emscripten (GH-31050) #31050

Merged
merged 9 commits into from
Feb 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1278,6 +1278,8 @@ def reap_children():
# Need os.waitpid(-1, os.WNOHANG): Windows is not supported
if not (hasattr(os, 'waitpid') and hasattr(os, 'WNOHANG')):
return
elif not has_subprocess_support:
return

# Reap all our dead child processes so we don't leave zombies around.
# These hog resources and might be causing some of the buildbots to die.
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/support/os_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ def __fspath__(self):
def fd_count():
"""Count the number of open file descriptors.
"""
if sys.platform.startswith(('linux', 'freebsd')):
if sys.platform.startswith(('linux', 'freebsd', 'emscripten')):
try:
names = os.listdir("/proc/self/fd")
# Subtract one because listdir() internally opens a file
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ def test_compile_top_level_await_no_coro(self):
msg=f"source={source} mode={mode}")


@unittest.skipIf(support.is_emscripten, "socket.accept is broken")
def test_compile_top_level_await(self):
"""Test whether code some top level await can be compiled.

Expand Down Expand Up @@ -1213,6 +1214,7 @@ def test_open_default_encoding(self):
os.environ.clear()
os.environ.update(old_environ)

@support.requires_subprocess()
def test_open_non_inheritable(self):
fileobj = open(__file__, encoding="utf-8")
with fileobj:
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_capi.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ def check_fatal_error(self, code, expected, not_expected=()):
self.assertNotIn(name, modules)
self.assertEqual(len(modules), total)

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


@support.requires_subprocess()
class PyMemDebugTests(unittest.TestCase):
PYTHONMALLOC = 'debug'
# '0x04c06e0' or '04C06E0'
Expand Down
3 changes: 3 additions & 0 deletions Lib/test/test_faulthandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
except ImportError:
_testcapi = None

if not support.has_subprocess_support:
raise unittest.SkipTest("test module requires subprocess")

TIMEOUT = 0.5
MS_WINDOWS = (os.name == 'nt')

Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_fileio.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from weakref import proxy
from functools import wraps

from test.support import cpython_only, swap_attr, gc_collect
from test.support import cpython_only, swap_attr, gc_collect, is_emscripten
from test.support.os_helper import (TESTFN, TESTFN_UNICODE, make_bad_fd)
from test.support.warnings_helper import check_warnings
from collections import UserList
Expand Down Expand Up @@ -373,7 +373,7 @@ def testAbles(self):
self.assertEqual(f.isatty(), False)
f.close()

if sys.platform != "win32":
if sys.platform != "win32" and not is_emscripten:
try:
f = self.FileIO("/dev/tty", "a")
except OSError:
Expand Down
17 changes: 12 additions & 5 deletions Lib/test/test_genericalias.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,20 @@
from fileinput import FileInput
from itertools import chain
from http.cookies import Morsel
from multiprocessing.managers import ValueProxy
from multiprocessing.pool import ApplyResult
try:
from multiprocessing.managers import ValueProxy
from multiprocessing.pool import ApplyResult
from multiprocessing.queues import SimpleQueue as MPSimpleQueue
except ImportError:
# _multiprocessing module is optional
ValueProxy = None
ApplyResult = None
MPSimpleQueue = None
try:
from multiprocessing.shared_memory import ShareableList
except ImportError:
# multiprocessing.shared_memory is not available on e.g. Android
ShareableList = None
from multiprocessing.queues import SimpleQueue as MPSimpleQueue
from os import DirEntry
from re import Pattern, Match
from types import GenericAlias, MappingProxyType, AsyncGeneratorType
Expand Down Expand Up @@ -79,13 +85,14 @@ class BaseTest(unittest.TestCase):
Queue, SimpleQueue,
_AssertRaisesContext,
SplitResult, ParseResult,
ValueProxy, ApplyResult,
WeakSet, ReferenceType, ref,
ShareableList, MPSimpleQueue,
ShareableList,
Future, _WorkItem,
Morsel]
if ctypes is not None:
generic_types.extend((ctypes.Array, ctypes.LibraryLoader))
if ValueProxy is not None:
generic_types.extend((ValueProxy, ApplyResult, MPSimpleQueue))

def test_subscriptable(self):
for t in self.generic_types:
Expand Down
3 changes: 3 additions & 0 deletions Lib/test/test_getpass.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ def test_username_priorities_of_env_values(self, environ):
getpass.getuser()
except ImportError: # in case there's no pwd module
pass
except KeyError:
# current user has no pwd entry
pass
self.assertEqual(
environ.get.call_args_list,
[mock.call(x) for x in ('LOGNAME', 'USER', 'LNAME', 'USERNAME')])
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,7 @@ def test_nested_class_definition_inside_function(self):
self.assertSourceEqual(mod2.cls213, 218, 222)
self.assertSourceEqual(mod2.cls213().func219(), 220, 221)

@unittest.skipIf(support.is_emscripten, "socket.accept is broken")
def test_nested_class_definition_inside_async_function(self):
import asyncio
self.addCleanup(asyncio.set_event_loop_policy, None)
Expand Down
3 changes: 2 additions & 1 deletion Lib/test/test_interpreters.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import unittest
import time

import _xxsubinterpreters as _interpreters
from test.support import import_helper
_interpreters = import_helper.import_module('_xxsubinterpreters')
from test.support import interpreters


Expand Down
13 changes: 13 additions & 0 deletions Lib/test/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ def _default_chunk_size():
with open(__file__, "r", encoding="latin-1") as f:
return f._CHUNK_SIZE

requires_alarm = unittest.skipUnless(
hasattr(signal, "alarm"), "test requires signal.alarm()"
)


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

@requires_alarm
def test_interrupted_write_unbuffered(self):
self.check_interrupted_write(b"xy", b"xy", mode="wb", buffering=0)

@requires_alarm
def test_interrupted_write_buffered(self):
self.check_interrupted_write(b"xy", b"xy", mode="wb")

@requires_alarm
def test_interrupted_write_text(self):
self.check_interrupted_write("xy", b"xy", mode="w", encoding="ascii")

Expand Down Expand Up @@ -4472,9 +4479,11 @@ def on_alarm(*args):
wio.close()
os.close(r)

@requires_alarm
def test_reentrant_write_buffered(self):
self.check_reentrant_write(b"xy", mode="wb")

@requires_alarm
def test_reentrant_write_text(self):
self.check_reentrant_write("xy", mode="w", encoding="ascii")

Expand Down Expand Up @@ -4502,10 +4511,12 @@ def alarm_handler(sig, frame):
os.close(w)
os.close(r)

@requires_alarm
def test_interrupted_read_retry_buffered(self):
self.check_interrupted_read_retry(lambda x: x.decode('latin1'),
mode="rb")

@requires_alarm
def test_interrupted_read_retry_text(self):
self.check_interrupted_read_retry(lambda x: x,
mode="r", encoding="latin1")
Expand Down Expand Up @@ -4578,9 +4589,11 @@ def alarm2(sig, frame):
if e.errno != errno.EBADF:
raise

@requires_alarm
def test_interrupted_write_retry_buffered(self):
self.check_interrupted_write_retry(b"x", mode="wb")

@requires_alarm
def test_interrupted_write_retry_text(self):
self.check_interrupted_write_retry("x", mode="w", encoding="latin1")

Expand Down
4 changes: 4 additions & 0 deletions Lib/test/test_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -992,6 +992,7 @@ def _empty_mapping(self):
@unittest.skipUnless(unix_shell and os.path.exists(unix_shell),
'requires a shell')
@unittest.skipUnless(hasattr(os, 'popen'), "needs os.popen()")
@support.requires_subprocess()
def test_update2(self):
os.environ.clear()
os.environ.update(HELLO="World")
Expand All @@ -1002,6 +1003,7 @@ def test_update2(self):
@unittest.skipUnless(unix_shell and os.path.exists(unix_shell),
'requires a shell')
@unittest.skipUnless(hasattr(os, 'popen'), "needs os.popen()")
@support.requires_subprocess()
def test_os_popen_iter(self):
with os.popen("%s -c 'echo \"line1\nline2\nline3\"'"
% unix_shell) as popen:
Expand Down Expand Up @@ -1173,6 +1175,8 @@ def test_iter_error_when_changing_os_environ_values(self):
def _test_underlying_process_env(self, var, expected):
if not (unix_shell and os.path.exists(unix_shell)):
return
elif not support.has_subprocess_support:
return

with os.popen(f"{unix_shell} -c 'echo ${var}'") as popen:
value = popen.read().strip()
Expand Down
9 changes: 5 additions & 4 deletions Lib/test/test_posix.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def test_truncate(self):
posix.truncate(os_helper.TESTFN, 0)

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


@unittest.skipUnless(hasattr(posix, 'waitid'), "test needs posix.waitid()")
@unittest.skipUnless(hasattr(os, 'fork'), "test needs os.fork()")
@support.requires_fork()
def test_waitid(self):
pid = os.fork()
if pid == 0:
Expand All @@ -209,7 +209,7 @@ def test_waitid(self):
res = posix.waitid(posix.P_PID, pid, posix.WEXITED)
self.assertEqual(pid, res.si_pid)

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

@unittest.skipUnless(hasattr(os, 'getegid'), "test needs os.getegid()")
@unittest.skipUnless(hasattr(os, 'popen'), "test needs os.popen()")
@support.requires_subprocess()
def test_getgroups(self):
with os.popen('id -G 2>/dev/null') as idg:
groups = idg.read().strip()
Expand Down Expand Up @@ -1481,7 +1482,7 @@ def test_unlink_dir_fd(self):
self.addCleanup(posix.unlink, fullname)
raise

@unittest.skipUnless(os.mkfifo in os.supports_dir_fd, "test needs dir_fd support in os.mkfifo()")
@unittest.skipUnless(hasattr(os, 'mkfifo') and os.mkfifo in os.supports_dir_fd, "test needs dir_fd support in os.mkfifo()")
def test_mkfifo_dir_fd(self):
with self.prepare() as (dir_fd, name, fullname):
try:
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_pwd.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def test_errors(self):

allnames = list(bynames.keys())
namei = 0
fakename = allnames[namei]
fakename = allnames[namei] if allnames else "invaliduser"
while fakename in bynames:
chars = list(fakename)
for i in range(len(chars)):
Expand Down
7 changes: 5 additions & 2 deletions Lib/test/test_pyexpat.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from xml.parsers import expat
from xml.parsers.expat import errors

from test.support import sortdict
from test.support import sortdict, is_emscripten


class SetAttributeTest(unittest.TestCase):
Expand Down Expand Up @@ -466,7 +466,10 @@ def test_exception(self):
"pyexpat.c", "StartElement")
self.check_traceback_entry(entries[2],
"test_pyexpat.py", "StartElementHandler")
if sysconfig.is_python_build() and not (sys.platform == 'win32' and platform.machine() == 'ARM'):
if (sysconfig.is_python_build()
and not (sys.platform == 'win32' and platform.machine() == 'ARM')
and not is_emscripten
):
self.assertIn('call_with_frame("StartElement"', entries[1][3])


Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ def test_fsize_toobig(self):
except (OverflowError, ValueError):
pass

@unittest.skipUnless(hasattr(resource, "getrusage"), "needs getrusage")
def test_getrusage(self):
self.assertRaises(TypeError, resource.getrusage)
self.assertRaises(TypeError, resource.getrusage, 42, 42)
Expand Down
8 changes: 5 additions & 3 deletions Lib/test/test_zipfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
from test.support import script_helper
from test.support import (findfile, requires_zlib, requires_bz2,
requires_lzma, captured_stdout, requires_subprocess)
from test.support.os_helper import TESTFN, unlink, rmtree, temp_dir, temp_cwd
from test.support.os_helper import (
TESTFN, unlink, rmtree, temp_dir, temp_cwd, fd_count
)


TESTFN2 = TESTFN + "2"
Expand Down Expand Up @@ -2539,14 +2541,14 @@ def test_write_after_read(self):
def test_many_opens(self):
# Verify that read() and open() promptly close the file descriptor,
# and don't rely on the garbage collector to free resources.
startcount = fd_count()
self.make_test_archive(TESTFN2)
with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
for x in range(100):
zipf.read('ones')
with zipf.open('ones') as zopen1:
pass
with open(os.devnull, "rb") as f:
self.assertLess(f.fileno(), 100)
self.assertEqual(startcount, fd_count())

def test_write_while_reading(self):
with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_DEFLATED) as zipf:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Fix wasm32-emscripten test failures and platform issues.
- Disable syscalls that are not supported or don't work, e.g.
wait, getrusage, prlimit, mkfifo, mknod, setres[gu]id, setgroups.
- Use fd_count to cound open fds.
- Add more checks for subprocess and fork.
- Add workarounds for missing _multiprocessing and failing socket.accept().
- Enable bzip2.
- Disable large file support.
- Disable signal.alarm.
10 changes: 9 additions & 1 deletion Modules/clinic/resource.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading