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

gh-71052: Add test exclusions to support running the test suite on Android #115918

Merged
merged 3 commits into from
Feb 29, 2024
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
13 changes: 11 additions & 2 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,24 +532,33 @@ def requires_debug_ranges(reason='requires co_positions / debug_ranges'):
is_emscripten = sys.platform == "emscripten"
is_wasi = sys.platform == "wasi"

# Apple mobile platforms (iOS/tvOS/watchOS) are POSIX-like but do not
# have subprocess or fork support.
is_apple_mobile = sys.platform in {"ios", "tvos", "watchos"}
is_apple = is_apple_mobile or sys.platform == "darwin"

has_fork_support = hasattr(os, "fork") and not (
# WASM and Apple mobile platforms do not support subprocesses.
is_emscripten
or is_wasi
or is_apple_mobile

# Although Android supports fork, it's unsafe to call it from Python because
# all Android apps are multi-threaded.
or is_android
)

def requires_fork():
return unittest.skipUnless(has_fork_support, "requires working os.fork()")

has_subprocess_support = not (
# WASM and Apple mobile platforms do not support subprocesses.
is_emscripten
or is_wasi
or is_apple_mobile

# Although Android supports subproceses, they're almost never useful in
# practice (see PEP 738). And most of the tests that use them are calling
# sys.executable, which won't work when Python is embedded in an Android app.
or is_android
)

def requires_subprocess():
Expand Down
17 changes: 17 additions & 0 deletions Lib/test/support/os_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,23 @@ def skip_unless_symlink(test):
return test if ok else unittest.skip(msg)(test)


_can_hardlink = None

def can_hardlink():
global _can_hardlink
if _can_hardlink is None:
# Android blocks hard links using SELinux
# (https://stackoverflow.com/q/32365690).
_can_hardlink = hasattr(os, "link") and not support.is_android
return _can_hardlink


def skip_unless_hardlink(test):
ok = can_hardlink()
msg = "requires hardlink support"
return test if ok else unittest.skip(msg)(test)


_can_xattr = None


Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_asyncio/test_subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from test import support
from test.support import os_helper

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

if support.MS_WINDOWS:
import msvcrt
Expand Down Expand Up @@ -47,7 +49,6 @@ def _start(self, *args, **kwargs):
self._proc.pid = -1


@support.requires_subprocess()
class SubprocessTransportTests(test_utils.TestCase):
def setUp(self):
super().setUp()
Expand Down Expand Up @@ -111,7 +112,6 @@ def test_subprocess_repr(self):
transport.close()


@support.requires_subprocess()
class SubprocessMixin:

def test_stdin_stdout(self):
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_compileall.py
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,7 @@ class CommandLineTestsNoSourceEpoch(CommandLineTestsBase,



@unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
@os_helper.skip_unless_hardlink
class HardlinkDedupTestsBase:
# Test hardlink_dupes parameter of compileall.compile_dir()

Expand Down
3 changes: 2 additions & 1 deletion Lib/test/test_fcntl.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ def test_fcntl_bad_file_overflow(self):
fcntl.fcntl(BadFile(INT_MIN - 1), fcntl.F_SETFL, os.O_NONBLOCK)

@unittest.skipIf(
platform.machine().startswith('arm') and platform.system() == 'Linux',
any(platform.machine().startswith(name) for name in {"arm", "aarch"})
and platform.system() in {"Linux", "Android"},
"ARM Linux returns EINVAL for F_NOTIFY DN_MULTISHOT")
def test_fcntl_64_bit(self):
# Issue #1309352: fcntl shouldn't fail when the third arg fits in a
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_interpreters/test_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ def test_sys_path_0(self):

class FinalizationTests(TestBase):

@support.requires_subprocess()
def test_gh_109793(self):
# Make sure finalization finishes and the correct error code
# is reported, even when subinterpreters get cleaned up at the end.
Expand Down
11 changes: 8 additions & 3 deletions Lib/test/test_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -1592,6 +1592,9 @@ def test_yields_correct_dir_fd(self):
@unittest.skipIf(
support.is_emscripten, "Cannot dup stdout on Emscripten"
)
@unittest.skipIf(
support.is_android, "dup return value is unpredictable on Android"
)
def test_fd_leak(self):
# Since we're opening a lot of FDs, we must be careful to avoid leaks:
# we both check that calling fwalk() a large number of times doesn't
Expand Down Expand Up @@ -2492,8 +2495,10 @@ def test_listdir(self):
# test listdir without arguments
current_directory = os.getcwd()
try:
os.chdir(os.sep)
self.assertEqual(set(os.listdir()), set(os.listdir(os.sep)))
# The root directory is not readable on Android, so use a directory
# we created ourselves.
os.chdir(self.dir)
self.assertEqual(set(os.listdir()), expected)
Comment on lines -2495 to +2501
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good

finally:
os.chdir(current_directory)

Expand Down Expand Up @@ -4838,7 +4843,7 @@ def check_entry(self, entry, name, is_dir, is_file, is_symlink):
os.name == 'nt')

def test_attributes(self):
link = hasattr(os, 'link')
link = os_helper.can_hardlink()
symlink = os_helper.can_symlink()

dirname = os.path.join(self.path, "dir")
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_pathlib/test_pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,7 @@ def test_rmdir(self):
self.assertFileNotFound(p.stat)
self.assertFileNotFound(p.unlink)

@unittest.skipUnless(hasattr(os, "link"), "os.link() is not present")
@os_helper.skip_unless_hardlink
def test_hardlink_to(self):
P = self.cls(self.base)
target = P / 'fileA'
Expand Down
12 changes: 6 additions & 6 deletions Lib/test/test_posix.py
Original file line number Diff line number Diff line change
Expand Up @@ -1270,9 +1270,10 @@ def test_get_and_set_scheduler_and_param(self):
self.assertIn(mine, possible_schedulers)
try:
parent = posix.sched_getscheduler(os.getppid())
except OSError as e:
if e.errno != errno.EPERM:
raise
except PermissionError:
# POSIX specifies EPERM, but Android returns EACCES. Both errno
# values are mapped to PermissionError.
pass
else:
self.assertIn(parent, possible_schedulers)
self.assertRaises(OSError, posix.sched_getscheduler, -1)
Expand All @@ -1287,9 +1288,8 @@ def test_get_and_set_scheduler_and_param(self):
try:
posix.sched_setscheduler(0, mine, param)
posix.sched_setparam(0, param)
except OSError as e:
if e.errno != errno.EPERM:
raise
except PermissionError:
pass
self.assertRaises(OSError, posix.sched_setparam, -1, param)

self.assertRaises(OSError, posix.sched_setscheduler, -1, mine, param)
Expand Down
8 changes: 3 additions & 5 deletions Lib/test/test_pty.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import sys
import unittest
from test.support import (
is_apple_mobile, is_emscripten, is_wasi, reap_children, verbose
is_android, is_apple_mobile, is_emscripten, is_wasi, reap_children, verbose
)
from test.support.import_helper import import_module
from test.support.os_helper import TESTFN, unlink

# Skip these tests if termios is not available
import_module('termios')

# Skip tests on WASM platforms, plus iOS/tvOS/watchOS
if is_apple_mobile or is_emscripten or is_wasi:
raise unittest.SkipTest(f"pty tests not required on {sys.platform}")
if is_android or is_apple_mobile or is_emscripten or is_wasi:
raise unittest.SkipTest("pty is not available on this platform")

import errno
import os
Expand Down
11 changes: 5 additions & 6 deletions Lib/test/test_venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
import tempfile
from test.support import (captured_stdout, captured_stderr,
skip_if_broken_multiprocessing_synchronize, verbose,
requires_subprocess, is_apple_mobile, is_emscripten,
is_wasi, requires_venv_with_pip, TEST_HOME_DIR,
requires_subprocess, is_android, is_apple_mobile,
is_emscripten, is_wasi,
requires_venv_with_pip, TEST_HOME_DIR,
requires_resource, copy_python_src_ignore)
from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree)
import unittest
Expand All @@ -39,10 +40,8 @@
or sys._base_executable != sys.executable,
'cannot run venv.create from within a venv on this platform')

# Skip tests on WASM platforms, plus iOS/tvOS/watchOS
if is_apple_mobile or is_emscripten or is_wasi:
raise unittest.SkipTest(f"venv tests not required on {sys.platform}")

if is_android or is_apple_mobile or is_emscripten or is_wasi:
raise unittest.SkipTest("venv is not available on this platform")

@requires_subprocess()
def check_output(cmd, encoding=None):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add test exclusions to support running the test suite on Android.