8000 [3.10] gh-114099: Add test exclusions to support running the test sui… · freakboy3742/cpython@cf0b9bd · GitHub
[go: up one dir, main page]

Skip to content

Commit cf0b9bd

Browse files
committed
[3.10] pythongh-114099: Add test exclusions to support running the test suite on iOS (python#114889)
Add test annotations required to run the test suite on iOS (PEP 730). The majority of the change involve annotating tests that use subprocess, but are skipped on Emscripten/WASI for other reasons, and including iOS/tvOS/watchOS under the same umbrella as macOS/darwin checks. `is_apple` and `is_apple_mobile` test helpers have been added to identify *any* Apple platform, and "any Apple platform except macOS", respectively.
1 parent 1329bc8 commit cf0b9bd

26 files changed

+146
-75
lines changed

Lib/test/support/__init__.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"check__all__", "skip_if_buggy_ucrt_strfptime",
4444
"check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer",
4545
# sys
46-
"is_jython", "is_android", "check_impl_detail", "unix_shell",
46+
"is_jython", "is_android", "is_apple_mobile", "check_impl_detail", "unix_shell",
4747
"setswitchinterval",
4848
# network
4949
"open_urlresource",
@@ -469,11 +469,27 @@ def requires_lzma(reason='requires lzma'):
469469

470470
is_android = hasattr(sys, 'getandroidapilevel')
471471

472-
if sys.platform not in ('win32', 'vxworks'):
472+
if sys.platform not in {"win32", "vxworks", "ios", "tvos", "watchos"}:
473473
unix_shell = '/system/bin/sh' if is_android else '/bin/sh'
474474
else:
475475
unix_shell = None
476476

477+
# Apple mobile platforms (iOS/tvOS/watchOS) are POSIX-like but do not
478+
# have subprocess or fork support.
479+
is_apple_mobile = sys.platform in {"ios", "tvos", "watchos"}
480+
is_apple = is_apple_mobile or sys.platform == "darwin"
481+
482+
has_fork_support = hasattr(os, "fork") and not is_apple_mobile
483+
484+
def requires_fork():
485+
return unittest.skipUnless(has_fork_support, "requires working os.fork()")
486+
487+
has_subprocess_support = not is_apple_mobile
488+
489+
def requires_subprocess():
490+
"""Used for subprocess, os.spawn calls, fd inheritance"""
491+
return unittest.skipUnless(has_subprocess_support, "requires subprocess support")
492+
477493
# Define the URL of a dedicated HTTP server for the network tests.
478494
# The URL must use clear-text HTTP: no redirection to encrypted HTTPS.
479495
TEST_HTTP_URL = "http://www.pythontest.net"

Lib/test/support/os_helper.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import os
55
import re
66
import stat
7+
import support
78
import sys
89
import time
910
import unittest
@@ -23,8 +24,8 @@
2324

2425
# TESTFN_UNICODE is a non-ascii filename
2526
TESTFN_UNICODE = TESTFN_ASCII + "-\xe0\xf2\u0258\u0141\u011f"
26-
if sys.platform == 'darwin':
27-
# In Mac OS X's VFS API file names are, by definition, canonically
27+
if support.is_apple:
28+
# On Apple's VFS API file names are, by definition, canonically
2829
# decomposed Unicode, encoded using UTF-8. See QA1173:
2930
# http://developer.apple.com/mac/library/qa/qa2001/qa1173.html
3031
import unicodedata
@@ -49,8 +50,8 @@
4950
'encoding (%s). Unicode filename tests may not be effective'
5051
% (TESTFN_UNENCODABLE, sys.getfilesystemencoding()))
5152
TESTFN_UNENCODABLE = None
52-
# Mac OS X denies unencodable filenames (invalid utf-8)
53-
elif sys.platform != 'darwin':
53+
# Apple denies unencodable filenames (invalid utf-8)
54+
elif not support.is_apple:
5455
try:
5556
# ascii and utf-8 cannot encode the byte 0xff
5657
b'\xff'.decode(sys.getfilesystemencoding())

Lib/test/test_asyncio/test_events.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,6 +1799,7 @@ def check_killed(self, returncode):
17991799
else:
18001800
self.assertEqual(-signal.SIGKILL, returncode)
18011801

1802+
@support.requires_subprocess()
18021803
def test_subprocess_exec(self):
18031804
prog = os.path.join(os.path.dirname(__file__), 'echo.py')
18041805

@@ -1820,6 +1821,7 @@ def test_subprocess_exec(self):
18201821
self.check_killed(proto.returncode)
18211822
self.assertEqual(b'Python The Winner', proto.data[1])
18221823

1824+
@support.requires_subprocess()
18231825
def test_subprocess_interactive(self):
18241826
prog = os.path.join(os.path.dirname(__file__), 'echo.py')
18251827

@@ -1847,6 +1849,7 @@ def test_subprocess_interactive(self):
18471849
self.loop.run_until_complete(proto.completed)
18481850
self.check_killed(proto.returncode)
18491851

1852+
@support.requires_subprocess()
18501853
def test_subprocess_shell(self):
18511854
connect = self.loop.subprocess_shell(
18521855
functools.partial(MySubprocessProtocol, self.loop),
@@ -1863,6 +1866,7 @@ def test_subprocess_shell(self):
18631866
self.assertEqual(proto.data[2], b'')
18641867
transp.close()
18651868

1869+
@support.requires_subprocess()
18661870
def test_subprocess_exitcode(self):< 83CB /div>
18671871
connect = self.loop.subprocess_shell(
18681872
functools.partial(MySubprocessProtocol, self.loop),
@@ -1874,6 +1878,7 @@ def test_subprocess_exitcode(self):
18741878
self.assertEqual(7, proto.returncode)
18751879
transp.close()
18761880

1881+
@support.requires_subprocess()
18771882
def test_subprocess_close_after_finish(self):
18781883
connect = self.loop.subprocess_shell(
18791884
functools.partial(MySubprocessProtocol, self.loop),
@@ -1888,6 +1893,7 @@ def test_subprocess_close_after_finish(self):
18881893
self.assertEqual(7, proto.returncode)
18891894
self.assertIsNone(transp.close())
18901895

1896+
@support.requires_subprocess()
18911897
def test_subprocess_kill(self):
18921898
prog = os.path.join(os.path.dirname(__file__), 'echo.py')
18931899

@@ -1904,6 +1910,7 @@ def test_subprocess_kill(self):
19041910
self.check_killed(proto.returncode)
19051911
transp.close()
19061912

1913+
@support.requires_subprocess()
19071914
def test_subprocess_terminate(self):
19081915
prog = os.path.join(os.path.dirname(__file__), 'echo.py')
19091916

@@ -1921,6 +1928,7 @@ def test_subprocess_terminate(self):
19211928
transp.close()
19221929

19231930
@unittest.skipIf(sys.platform == 'win32', "Don't have SIGHUP")
1931+
@support.requires_subprocess()
19241932
def test_subprocess_send_signal(self):
19251933
# bpo-31034: Make sure that we get the default signal handler (killing
19261934
# the process). The parent process may have decided to ignore SIGHUP,
@@ -1945,6 +1953,7 @@ def test_subprocess_send_signal(self):
19451953
finally:
19461954
signal.signal(signal.SIGHUP, old_handler)
19471955

1956+
@support.requires_subprocess()
19481957
def test_subprocess_stderr(self):
19491958
prog = os.path.join(os.path.dirname(__file__), 'echo2.py')
19501959

@@ -1966,6 +1975,7 @@ def test_subprocess_stderr(self):
19661975
self.assertTrue(proto.data[2].startswith(b'ERR:test'), proto.data[2])
19671976
self.assertEqual(0, proto.returncode)
19681977

1978+
@support.requires_subprocess()
19691979
def test_subprocess_stderr_redirect_to_stdout(self):
19701980
prog = os.path.join(os.path.dirname(__file__), 'echo2.py')
19711981

@@ -1991,6 +2001,7 @@ def test_subprocess_stderr_redirect_to_stdout(self):
19912001
transp.close()
19922002
self.assertEqual(0, proto.returncode)
19932003

2004+
@support.requires_subprocess()
19942005
def test_subprocess_close_client_stream(self):
19952006
prog = os.path.join(os.path.dirname(__file__), 'echo3.py')
19962007

@@ -2025,6 +2036,7 @@ def test_subprocess_close_client_stream(self):
20252036
self.loop.run_until_complete(proto.completed)
20262037
self.check_killed(proto.returncode)
20272038

2039+
@support.requires_subprocess()
20282040
def test_subprocess_wait_no_same_group(self):
20292041
# start the new process in a new session
20302042
connect = self.loop.subprocess_shell(
@@ -2037,6 +2049,7 @@ def test_subprocess_wait_no_same_group(self):
20372049
self.assertEqual(7, proto.returncode)
20382050
transp.close()
20392051

2052+
@support.requires_subprocess()
20402053
def test_subprocess_exec_invalid_args(self):
20412054
async def connect(**kwds):
20422055
await self.loop.subprocess_exec(
@@ -2050,6 +2063,7 @@ async def connect(**kwds):
20502063
with self.assertRaises(ValueError):
20512064
self.loop.run_until_complete(connect(shell=True))
20522065

2066+
@support.requires_subprocess()
20532067
def test_subprocess_shell_invalid_args(self):
20542068

20552069
async def connect(cmd=None, **kwds):

Lib/test/test_asyncio/test_streams.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import threading
1010
import unittest
1111
from unittest import mock
12-
from test.support import socket_helper
12+
from test.support import requires_subprocess, socket_helper
1313
try:
1414
import ssl
1515
except ImportError:
@@ -707,6 +707,7 @@ async def client(path):
707707
self.assertEqual(messages, [])
708708

709709
@unittest.skipIf(sys.platform == 'win32', "Don't have pipes")
710+
@requires_subprocess()
710711
def test_read_all_from_pipe_reader(self):
711712
# See asyncio issue 168. This test is derived from the example
712713
# subprocess_attach_read_pipe.py, but we configure the

Lib/test/test_asyncio/test_subprocess.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def _start(self, *args, **kwargs):
3939
self._proc.pid = -1
4040

4141

42+
@support.requires_subprocess()
4243
class SubprocessTransportTests(test_utils.TestCase):
4344
def setUp(self):
4445
super().setUp()
@@ -104,6 +105,7 @@ def test_subprocess_repr(self):
104105
transport.close()
105106

106107

108+
@support.requires_subprocess()
107109
class SubprocessMixin:
108110

109111
def test_stdin_stdout(self):

Lib/test/test_cmd_line_script.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414

1515
import textwrap
1616
from test import support
17-
from test.support import import_helper
18-
from test.support import os_helper
17+
from test.support import import_helper, is_apple, os_helper
1918
from test.support.script_helper import (
2019
make_pkg, make_script, make_zip_pkg, make_zip_script,
2120
assert_python_ok, assert_python_failure, spawn_python, kill_python)
@@ -554,11 +553,14 @@ def test_pep_409_verbiage(self):
554553
self.assertTrue(text[3].startswith('NameError'))
555554

556555
def test_non_ascii(self):
557-
# Mac OS X denies the creation of a file with an invalid UTF-8 name.
556+
# Apple platforms deny the creation of a file with an invalid UTF-8 name.
558557
# Windows allows creating a name with an arbitrary bytes name, but
559558
# Python cannot a undecodable bytes argument to a subprocess.
560-
if (os_helper.TESTFN_UNDECODABLE
561-
and sys.platform not in ('win32', 'darwin')):
559+
if (
560+
os_helper.TESTFN_UNDECODABLE
561+
and sys.platform not in {"win32"}
562+
and not is_apple
563+
):
562564
name = os.fsdecode(os_helper.TESTFN_UNDECODABLE)
563565
elif os_helper.TESTFN_NONASCII:
564566
name = os_helper.TESTFN_NONASCII

Lib/test/test_fcntl.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import sys
77
import unittest
88
from multiprocessing import Process
9-
from test.support import verbose, cpython_only
9+
from test.support import cpython_only, requires_subprocess, verbose
1010
from test.support.import_helper import import_module
1111
from test.support.os_helper import TESTFN, unlink
1212

@@ -156,6 +156,7 @@ def test_flock(self):
156156
self.assertRaises(TypeError, fcntl.flock, 'spam', fcntl.LOCK_SH)
157157

158158
@unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError")
159+
@requires_subprocess()
159160
def test_lockf_exclusive(self):
160161
self.f = open(TESTFN, 'wb+')
161162
cmd = fcntl.LOCK_EX | fcntl.LOCK_NB
@@ -167,6 +168,7 @@ def test_lockf_exclusive(self):
167168
self.assertEqual(p.exitcode, 0)
168169

169170
@unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError")
171+
@requires_subprocess()
170172
def test_lockf_share(self):
171173
self.f = open(TESTFN, 'wb+')
172174
cmd = fcntl.LOCK_SH | fcntl.LOCK_NB

Lib/test/test_ftplib.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from unittest import TestCase, skipUnless
2020
from test import support
21+
from test.support import requires_subprocess
2122
from test.support import threading_helper
2223
from test.support import socket_helper
2324
from test.support import warnings_helper
@@ -904,6 +905,7 @@ def callback(data):
904905

905906

906907
@skipUnless(ssl, "SSL not available")
908+
@requires_subprocess()
907909
class TestTLS_FTPClassMixin(TestFTPClass):
908910
"""Repeat TestFTPClass tests starting the TLS layer for both control
909911
and data connections first.
@@ -920,6 +922,7 @@ def setUp(self, encoding=DEFAULT_ENCODING):
920922

921923

922924
@skipUnless(ssl, "SSL not available")
925+
@requires_subprocess()
923926
class TestTLS_FTPClass(TestCase):
924927
"""Specific TLS_FTP class tests."""
925928

Lib/test/test_genericpath.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
import sys
88
import unittest
99
import warnings
10-
from test.support import os_helper
11-
from test.support import warnings_helper
10+
from test.support import (
11+
is_apple, os_helper, warnings_helper
12+
)
1213
from test.support.script_helper import assert_python_ok
1314
from test.support.os_helper import FakePath
1415

@@ -475,12 +476,14 @@ def test_abspath_issue3426(self):
475476
self.assertIsInstance(abspath(path), str)
476477

477478
def test_nonascii_abspath(self):
478-
if (os_helper.TESTFN_UNDECODABLE
479-
# Mac OS X denies the creation of a directory with an invalid
480-
# UTF-8 name. Windows allows creating a directory with an
481-
# arbitrary bytes name, but fails to enter this directory
482-
# (when the bytes name is used).
483-
and sys.platform not in ('win32', 'darwin')):
479+
if (
480+
os_helper.TESTFN_UNDECODABLE
481+
# Apple platforms deny the creation of a
482+
# directory with an invalid UTF-8 name. Windows allows creating a
483+
# directory with an arbitrary bytes name, but fails to enter this
484+
# directory (when the bytes name is used).
485+
and sys.platform not in {"win32"} and not is_apple
486+
):
484487
name = os_helper.TESTFN_UNDECODABLE
485488
elif os_helper.TESTFN_NONASCII:
486489
name = os_helper.TESTFN_NONASCII

Lib/test/test_httpservers.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@
3030

3131
import unittest
3232
from test import support
33-
from test.support import os_helper
34-
from test.support import threading_helper
33+
from test.support import (
34+
is_apple, os_helper, requires_subprocess, threading_helper
35+
)
3536

3637

3738
class NoLogRequestHandler:
@@ -388,8 +389,8 @@ def close_conn():
388389
reader.close()
389390
return body
390391

391-
@unittest.skipIf(sys.platform == 'darwin',
392-
'undecodable name cannot always be decoded on macOS')
392+
@unittest.skipIf(is_apple,
393+
'undecodable name cannot always be decoded on Apple platforms')
393394
@unittest.skipIf(sys.platform == 'win32',
394395
'undecodable name cannot be decoded on win32')
395396
@unittest.skipUnless(os_helper.TESTFN_UNDECODABLE,
@@ -400,11 +401,11 @@ def test_undecodable_filename(self):
400401
with open(os.path.join(self.tempdir, filename), 'wb') as f:
401402
f.write(os_helper.TESTFN_UNDECODABLE)
402403
response = self.request(self.base_url + '/')
403-
if sys.platform == 'darwin':
404-
# On Mac OS the HFS+ filesystem replaces bytes that aren't valid
405-
# UTF-8 into a percent-encoded value.
404+
if is_apple:
405+
# On Apple platforms the HFS+ filesystem replaces bytes that
406+
# aren't valid UTF-8 into a percent-encoded value.
406407
for name in os.listdir(self.tempdir):
407-
if name != 'test': # Ignore a filename created in setUp().
408+
if name != 'test': # Ignore a filename created in setUp().
408409
filename = name
409410
break
410411
body = self.check_status_and_reason(response, HTTPStatus.OK)
@@ -670,6 +671,7 @@ def test_html_escape_filename(self):
670671

671672
@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
672673
"This test can't be run reliably as root (issue #13308).")
674+
@requires_subprocess()
673675
class CGIHTTPServerTestCase(BaseTestCase):
674676
class request_handler(NoLogRequestHandler, CGIHTTPRequestHandler):
675677
pass

0 commit comments

Comments
 (0)
0