summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Heimes <christian@python.org>2022-06-06 17:24:11 (GMT)
committerGitHub <noreply@github.com>2022-06-06 17:24:11 (GMT)
commit22fed605e096eb74f3aa33f6d25aee76fdc2a3fa (patch)
treecd15eb66416ec5aa0ad33e48b0c76f98bb811b45
parent56b5daf15970be449d44e91f08db84c698ac5506 (diff)
downloadcpython-22fed605e096eb74f3aa33f6d25aee76fdc2a3fa.zip
cpython-22fed605e096eb74f3aa33f6d25aee76fdc2a3fa.tar.gz
cpython-22fed605e096eb74f3aa33f6d25aee76fdc2a3fa.tar.bz2
gh-90473: Make chmod a dummy on WASI, skip chmod tests (GH-93534)
WASI does not have the ``chmod(2)`` syscall yet.
-rw-r--r--Lib/test/support/os_helper.py36
-rw-r--r--Lib/test/test_argparse.py1
-rw-r--r--Lib/test/test_dbm_dumb.py2
-rw-r--r--Lib/test/test_import/__init__.py3
-rw-r--r--Lib/test/test_netrc.py1
-rw-r--r--Lib/test/test_os.py5
-rw-r--r--Lib/test/test_pathlib.py3
-rw-r--r--Lib/test/test_posix.py4
-rw-r--r--Lib/test/test_posixpath.py3
-rw-r--r--Lib/test/test_py_compile.py1
-rw-r--r--Lib/test/test_pydoc.py1
-rw-r--r--Lib/test/test_shutil.py1
-rw-r--r--Lib/test/test_stat.py2
-rw-r--r--Lib/test/test_tarfile.py2
-rw-r--r--Lib/test/test_tempfile.py2
-rw-r--r--Lib/test/test_uu.py6
-rw-r--r--Lib/test/test_zipapp.py2
-rw-r--r--Misc/NEWS.d/next/Tests/2022-06-05-10-16-45.gh-issue-90473.QMu7A8.rst2
-rw-r--r--Modules/posixmodule.c4
-rw-r--r--Tools/wasm/config.site-wasm32-wasi5
20 files changed, 81 insertions, 5 deletions
diff --git a/Lib/test/support/os_helper.py b/Lib/test/support/os_helper.py
index a6ec1cf..ff2fc33 100644
--- a/Lib/test/support/os_helper.py
+++ b/Lib/test/support/os_helper.py
@@ -237,6 +237,42 @@ def skip_unless_xattr(test):
return test if ok else unittest.skip(msg)(test)
+_can_chmod = None
+
+def can_chmod():
+ global _can_chmod
+ if _can_chmod is not None:
+ return _can_chmod
+ if not hasattr(os, "chown"):
+ _can_chmod = False
+ return _can_chmod
+ try:
+ with open(TESTFN, "wb") as f:
+ try:
+ os.chmod(TESTFN, 0o777)
+ mode1 = os.stat(TESTFN).st_mode
+ os.chmod(TESTFN, 0o666)
+ mode2 = os.stat(TESTFN).st_mode
+ except OSError as e:
+ can = False
+ else:
+ can = stat.S_IMODE(mode1) != stat.S_IMODE(mode2)
+ finally:
+ os.unlink(TESTFN)
+ _can_chmod = can
+ return can
+
+
+def skip_unless_working_chmod(test):
+ """Skip tests that require working os.chmod()
+
+ WASI SDK 15.0 cannot change file mode bits.
+ """
+ ok = can_chmod()
+ msg = "requires working os.chmod()"
+ return test if ok else unittest.skip(msg)(test)
+
+
def unlink(filename):
try:
_unlink(filename)
diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py
index 273db45..299eb30 100644
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -45,6 +45,7 @@ class TestCase(unittest.TestCase):
env['COLUMNS'] = '80'
+@os_helper.skip_unless_working_chmod
class TempDirMixin(object):
def setUp(self):
diff --git a/Lib/test/test_dbm_dumb.py b/Lib/test/test_dbm_dumb.py
index 73cff63..a481175 100644
--- a/Lib/test/test_dbm_dumb.py
+++ b/Lib/test/test_dbm_dumb.py
@@ -42,6 +42,7 @@ class DumbDBMTestCase(unittest.TestCase):
self.read_helper(f)
@unittest.skipUnless(hasattr(os, 'umask'), 'test needs os.umask()')
+ @os_helper.skip_unless_working_chmod
def test_dumbdbm_creation_mode(self):
try:
old_umask = os.umask(0o002)
@@ -265,6 +266,7 @@ class DumbDBMTestCase(unittest.TestCase):
"'r', 'w', 'c', or 'n'"):
dumbdbm.open(_fname, flag)
+ @os_helper.skip_unless_working_chmod
def test_readonly_files(self):
with os_helper.temp_dir() as dir:
fname = os.path.join(dir, 'db')
diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py
index 35c260b..be2e91d 100644
--- a/Lib/test/test_import/__init__.py
+++ b/Lib/test/test_import/__init__.py
@@ -557,6 +557,7 @@ class FilePermissionTests(unittest.TestCase):
@unittest.skipUnless(os.name == 'posix',
"test meaningful only on posix systems")
+ @os_helper.skip_unless_working_chmod
def test_cached_mode_issue_2051(self):
# permissions of .pyc should match those of .py, regardless of mask
mode = 0o600
@@ -573,6 +574,7 @@ class FilePermissionTests(unittest.TestCase):
@unittest.skipUnless(os.name == 'posix',
"test meaningful only on posix systems")
+ @os_helper.skip_unless_working_chmod
def test_cached_readonly(self):
mode = 0o400
with temp_umask(0o022), _ready_to_import() as (name, path):
@@ -886,6 +888,7 @@ class PycacheTests(unittest.TestCase):
@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
"due to varying filesystem permission semantics (issue #11956)")
@skip_if_dont_write_bytecode
+ @os_helper.skip_unless_working_chmod
def test_unwritable_directory(self):
# When the umask causes the new __pycache__ directory to be
# unwritable, the import still succeeds but no .pyc file is written.
diff --git a/Lib/test/test_netrc.py b/Lib/test/test_netrc.py
index 05a23e5..573d636 100644
--- a/Lib/test/test_netrc.py
+++ b/Lib/test/test_netrc.py
@@ -272,6 +272,7 @@ class NetrcTestCase(unittest.TestCase):
@unittest.skipUnless(os.name == 'posix', 'POSIX only test')
@unittest.skipIf(pwd is None, 'security check requires pwd module')
+ @os_helper.skip_unless_working_chmod
def test_security(self):
# This test is incomplete since we are normally not run as root and
# therefore can't test the file ownership being wrong.
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index c0321dc..29f69a8 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -1670,7 +1670,7 @@ class MakedirTests(unittest.TestCase):
os.removedirs(path)
-@unittest.skipUnless(hasattr(os, 'chown'), "Test needs chown")
+@os_helper.skip_unless_working_chmod
class ChownFileTests(unittest.TestCase):
@classmethod
@@ -3784,7 +3784,6 @@ class OSErrorTests(unittest.TestCase):
def test_oserror_filename(self):
funcs = [
(self.filenames, os.chdir,),
- (self.filenames, os.chmod, 0o777),
(self.filenames, os.lstat,),
(self.filenames, os.open, os.O_RDONLY),
(self.filenames, os.rmdir,),
@@ -3805,6 +3804,8 @@ class OSErrorTests(unittest.TestCase):
(self.filenames, os.rename, "dst"),
(self.filenames, os.replace, "dst"),
))
+ if os_helper.can_chmod():
+ funcs.append((self.filenames, os.chmod, 0o777))
if hasattr(os, "chown"):
funcs.append((self.filenames, os.chown, 0, 0))
if hasattr(os, "lchown"):
diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py
index 2215134..a426198 100644
--- a/Lib/test/test_pathlib.py
+++ b/Lib/test/test_pathlib.py
@@ -1902,6 +1902,7 @@ class _BasePathTest(object):
with p:
pass
+ @os_helper.skip_unless_working_chmod
def test_chmod(self):
p = self.cls(BASE) / 'fileA'
mode = p.stat().st_mode
@@ -1916,6 +1917,7 @@ class _BasePathTest(object):
# On Windows, os.chmod does not follow symlinks (issue #15411)
@only_posix
+ @os_helper.skip_unless_working_chmod
def test_chmod_follow_symlinks_true(self):
p = self.cls(BASE) / 'linkA'
q = p.resolve()
@@ -1931,6 +1933,7 @@ class _BasePathTest(object):
# XXX also need a test for lchmod.
+ @os_helper.skip_unless_working_chmod
def test_stat(self):
p = self.cls(BASE) / 'fileA'
st = p.stat()
diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py
index 7efe3c5..4130cdd 100644
--- a/Lib/test/test_posix.py
+++ b/Lib/test/test_posix.py
@@ -786,7 +786,7 @@ class PosixTester(unittest.TestCase):
self.assertRaises(TypeError, chown_func, first_param, uid, t(gid))
check_stat(uid, gid)
- @unittest.skipUnless(hasattr(posix, 'chown'), "test needs os.chown()")
+ @os_helper.skip_unless_working_chmod
def test_chown(self):
# raise an OSError if the file does not exist
os.unlink(os_helper.TESTFN)
@@ -796,6 +796,7 @@ class PosixTester(unittest.TestCase):
os_helper.create_empty_file(os_helper.TESTFN)
self._test_all_chown_common(posix.chown, os_helper.TESTFN, posix.stat)
+ @os_helper.skip_unless_working_chmod
@unittest.skipUnless(hasattr(posix, 'fchown'), "test needs os.fchown()")
def test_fchown(self):
os.unlink(os_helper.TESTFN)
@@ -809,6 +810,7 @@ class PosixTester(unittest.TestCase):
finally:
test_file.close()
+ @os_helper.skip_unless_working_chmod
@unittest.skipUnless(hasattr(posix, 'lchown'), "test needs os.lchown()")
def test_lchown(self):
os.unlink(os_helper.TESTFN)
diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py
index 97d3e9e..c644f88 100644
--- a/Lib/test/test_posixpath.py
+++ b/Lib/test/test_posixpath.py
@@ -193,8 +193,7 @@ class PosixPathTest(unittest.TestCase):
self.assertIs(posixpath.ismount('/\x00'), False)
self.assertIs(posixpath.ismount(b'/\x00'), False)
- @unittest.skipUnless(os_helper.can_symlink(),
- "Test requires symlink support")
+ @os_helper.skip_unless_symlink
def test_ismount_symlinks(self):
# Symlinks are never mountpoints.
try:
diff --git a/Lib/test/test_py_compile.py b/Lib/test/test_py_compile.py
index 794d643..f494aed 100644
--- a/Lib/test/test_py_compile.py
+++ b/Lib/test/test_py_compile.py
@@ -119,6 +119,7 @@ class PyCompileTestsBase:
'non-root user required')
@unittest.skipIf(os.name == 'nt',
'cannot control directory permissions on Windows')
+ @os_helper.skip_unless_working_chmod
def test_exceptions_propagate(self):
# Make sure that exceptions raised thanks to issues with writing
# bytecode.
diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py
index ac181ef..b705b7a 100644
--- a/Lib/test/test_pydoc.py
+++ b/Lib/test/test_pydoc.py
@@ -933,6 +933,7 @@ class PydocImportTest(PydocBaseTest):
self.assertEqual(out.getvalue(), '')
self.assertEqual(err.getvalue(), '')
+ @os_helper.skip_unless_working_chmod
def test_apropos_empty_doc(self):
pkgdir = os.path.join(TESTFN, 'walkpkg')
os.mkdir(pkgdir)
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index c943905..18421fc 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -311,6 +311,7 @@ class TestRmTree(BaseTest, unittest.TestCase):
"This test can't be run on Cygwin (issue #1071513).")
@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
"This test can't be run reliably as root (issue #1076467).")
+ @os_helper.skip_unless_working_chmod
def test_on_error(self):
self.errorState = 0
os.mkdir(TESTFN)
diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py
index 193a0fc..4ba37ae 100644
--- a/Lib/test/test_stat.py
+++ b/Lib/test/test_stat.py
@@ -113,6 +113,7 @@ class TestFilemode:
else:
self.assertFalse(func(mode))
+ @os_helper.skip_unless_working_chmod
def test_mode(self):
with open(TESTFN, 'w'):
pass
@@ -151,6 +152,7 @@ class TestFilemode:
self.assertEqual(self.statmod.S_IFMT(st_mode),
self.statmod.S_IFREG)
+ @os_helper.skip_unless_working_chmod
def test_directory(self):
os.mkdir(TESTFN)
os.chmod(TESTFN, 0o700)
diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
index a364043..5c08468 100644
--- a/Lib/test/test_tarfile.py
+++ b/Lib/test/test_tarfile.py
@@ -630,6 +630,7 @@ class MiscReadTestBase(CommonReadTest):
data = f.read()
self.assertEqual(sha256sum(data), sha256_regtype)
+ @os_helper.skip_unless_working_chmod
def test_extractall(self):
# Test if extractall() correctly restores directory permissions
# and times (see issue1735).
@@ -660,6 +661,7 @@ class MiscReadTestBase(CommonReadTest):
tar.close()
os_helper.rmtree(DIR)
+ @os_helper.skip_unless_working_chmod
def test_extract_directory(self):
dirtype = "ustar/dirtype"
DIR = os.path.join(TEMPDIR, "extractdir")
diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py
index f056e5c..20f88d8 100644
--- a/Lib/test/test_tempfile.py
+++ b/Lib/test/test_tempfile.py
@@ -450,6 +450,7 @@ class TestMkstempInner(TestBadTempdir, BaseTestCase):
support.gc_collect() # For PyPy or other GCs.
os.rmdir(dir)
+ @os_helper.skip_unless_working_chmod
def test_file_mode(self):
# _mkstemp_inner creates files with the proper mode
@@ -787,6 +788,7 @@ class TestMkdtemp(TestBadTempdir, BaseTestCase):
finally:
os.rmdir(dir)
+ @os_helper.skip_unless_working_chmod
def test_mode(self):
# mkdtemp creates directories with the proper mode
diff --git a/Lib/test/test_uu.py b/Lib/test/test_uu.py
index 316a04a..0493aae 100644
--- a/Lib/test/test_uu.py
+++ b/Lib/test/test_uu.py
@@ -74,6 +74,7 @@ class UUTest(unittest.TestCase):
with self.assertRaises(TypeError):
uu.encode(inp, out, "t1", 0o644, True)
+ @os_helper.skip_unless_working_chmod
def test_decode(self):
for backtick in True, False:
inp = io.BytesIO(encodedtextwrapped(0o666, "t1", backtick=backtick))
@@ -199,6 +200,8 @@ class UUFileTest(unittest.TestCase):
s = fout.read()
self.assertEqual(s, encodedtextwrapped(0o644, self.tmpin))
+ # decode() calls chmod()
+ @os_helper.skip_unless_working_chmod
def test_decode(self):
with open(self.tmpin, 'wb') as f:
f.write(encodedtextwrapped(0o644, self.tmpout))
@@ -211,6 +214,7 @@ class UUFileTest(unittest.TestCase):
self.assertEqual(s, plaintext)
# XXX is there an xp way to verify the mode?
+ @os_helper.skip_unless_working_chmod
def test_decode_filename(self):
with open(self.tmpin, 'wb') as f:
f.write(encodedtextwrapped(0o644, self.tmpout))
@@ -221,6 +225,7 @@ class UUFileTest(unittest.TestCase):
s = f.read()
self.assertEqual(s, plaintext)
+ @os_helper.skip_unless_working_chmod
def test_decodetwice(self):
# Verify that decode() will refuse to overwrite an existing file
with open(self.tmpin, 'wb') as f:
@@ -231,6 +236,7 @@ class UUFileTest(unittest.TestCase):
with open(self.tmpin, 'rb') as f:
self.assertRaises(uu.Error, uu.decode, f)
+ @os_helper.skip_unless_working_chmod
def test_decode_mode(self):
# Verify that decode() will set the given mode for the out_file
expected_mode = 0o444
diff --git a/Lib/test/test_zipapp.py b/Lib/test/test_zipapp.py
index d135c68..f1c6b2d 100644
--- a/Lib/test/test_zipapp.py
+++ b/Lib/test/test_zipapp.py
@@ -9,6 +9,7 @@ import unittest
import zipapp
import zipfile
from test.support import requires_zlib
+from test.support import os_helper
from unittest.mock import patch
@@ -317,6 +318,7 @@ class ZipAppTest(unittest.TestCase):
# (Unix only) tests that archives with shebang lines are made executable
@unittest.skipIf(sys.platform == 'win32',
'Windows does not support an executable bit')
+ @os_helper.skip_unless_working_chmod
def test_shebang_is_executable(self):
# Test that an archive with a shebang line is made executable.
source = self.tmpdir / 'source'
diff --git a/Misc/NEWS.d/next/Tests/2022-06-05-10-16-45.gh-issue-90473.QMu7A8.rst b/Misc/NEWS.d/next/Tests/2022-06-05-10-16-45.gh-issue-90473.QMu7A8.rst
new file mode 100644
index 0000000..6c76b7f
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2022-06-05-10-16-45.gh-issue-90473.QMu7A8.rst
@@ -0,0 +1,2 @@
+WASI does not have a ``chmod(2)`` syscall. :func:`os.chmod` is now a dummy
+function on WASI. Skip all tests that depend on working :func:`os.chmod`.
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 6883ad0..d41e19e 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -3282,6 +3282,10 @@ os_chmod_impl(PyObject *module, path_t *path, int mode, int dir_fd,
{
#ifdef HAVE_CHMOD
result = chmod(path->narrow, mode);
+#elif defined(__wasi__)
+ // WASI SDK 15.0 does not support chmod.
+ // Ignore missing syscall for now.
+ result = 0;
#else
result = -1;
errno = ENOSYS;
diff --git a/Tools/wasm/config.site-wasm32-wasi b/Tools/wasm/config.site-wasm32-wasi
index a6fcbed..f151b7b 100644
--- a/Tools/wasm/config.site-wasm32-wasi
+++ b/Tools/wasm/config.site-wasm32-wasi
@@ -35,6 +35,11 @@ ac_cv_func_fdopendir=no
# WASIX stubs we don't want to use.
ac_cv_func_kill=no
+# WASI SDK 15.0 does not have chmod.
+# Ignore WASIX stubs for now.
+ac_cv_func_chmod=no
+ac_cv_func_fchmod=no
+
# WASI sockets are limited to operations on given socket fd and inet sockets.
# Disable AF_UNIX and AF_PACKET support, see socketmodule.h.
ac_cv_header_sys_un_h=no