3.15.0b2 make test failures on FreeBSD's tmpfs: test.test_os.test_posix test_tempfile
還沒有人認領這個 Issue。
- 主要語言
- Python
- 星號
- 77.2k
- 分支
- 35.9k
- PR 合併指標
- PR 指標待擷取
描述
Bug report
Bug description:
Greetings,
on FreeBSD 14.4 and FreeBSD 15.0 amd64, inside a "poudriere" jail (a jail is a tighter lockdown than a chroot), make test comes back with two tests (2 x 2 units failing) failed when the Python build and tests are run on a tmpfs type file system, which is a common configuration in Poudriere, and Poudriere is the script collection that sets up a clean-room build environment to build some package. This was reported by Gleb Popov and I can reproduce it.
Note: the test_posix part is NOT a duplicate of https://github.com/python/cpython/issues/148841
IMO, test_posix is arguably inadequate for FreeBSD and needs fixing;
the test_tempfile might either see fixing in the Python module that maps os.chflags() errno returns to exceptions and map errno == EOPNOTSUPP to a "NotImplementedError" exception, or the test might be extended such that it traps OSError as exc and discards the exception in case exc.errno == errno.EOPNOTSUPP.
Here are the details:
- The
lseek(_,_,SEEK_HOLE)test is off on FreeBSD, which documents, in lseek(2):
[...] The existence of a hole at the end of every data region allows
for easy programming and also provides compatibility to the original
implementation in Solaris. It also causes the current file size (i.e.,
end-of-file offset) to be returned to indicate that there are no more
holes past the supplied offset. Applications should use
fpathconf(_PC_MIN_HOLE_SIZE) or pathconf(_PC_MIN_HOLE_SIZE) to determine
if a file system supports SEEK_HOLE. See pathconf(2).
This is the test code (I am marking up the offending line with Python comment):
@unittest.skipUnless(hasattr(os, 'SEEK_HOLE'),
"test needs an OS that reports file holes")
def test_fs_holes(self):
# Even if the filesystem doesn't report holes,
# if the OS supports it the SEEK_* constants
# will be defined and will have a consistent
# behaviour:
# os.SEEK_DATA = current position
# os.SEEK_HOLE = end of file position
with open(os_helper.TESTFN, 'r+b') as fp:
fp.write(b"hello")
fp.flush()
size = fp.tell()
fno = fp.fileno()
try :
for i in range(size):
self.assertEqual(i, os.lseek(fno, i, os.SEEK_DATA))
self.assertLessEqual(size, os.lseek(fno, i, os.SEEK_HOLE))
self.assertRaises(OSError, os.lseek, fno, size, os.SEEK_DATA)
self.assertRaises(OSError, os.lseek, fno, size, os.SEEK_HOLE) # <-- this is the line that won't raise (and rightfully so)
except OSError :
# Some OSs claim to support SEEK_HOLE/SEEK_DATA
# but it is not true.
# For instance:
# http://lists.freebsd.org/pipermail/freebsd-amd64/2012-January/014332.html
raise unittest.SkipTest("OSError raised!")
So lseek(fno, filesize, SEEK_HOLE) will not return an error, but succeed and return the file size because it's looking at the "[virtual] hole at the end of every data region".
- Re the makedev failure (see below): the FreeBSD operating system documents, on MAKEDEV(3) (which also documents major() and minor()) that major will return an int and this:
The major() and minor() macros return numbers whose value can span the
complete range of an int.
So that major() cannot ever fail and testing the return value for anything representable by a C-language int is plain wrong. The failing situation for this test is:
@unittest.skipUnless(hasattr(posix, 'makedev'), 'test needs posix.makedev()')
def test_makedev(self):
st = posix.stat(os_helper.TESTFN)
dev = st.st_dev
self.assertIsInstance(dev, int)
self.assertGreaterEqual(dev, 0)
major = posix.major(dev)
self.assertIsInstance(major, int)
self.assertGreaterEqual(major, 0) # <-- this is the offending line
and if I try this part manually, this is what I get:
>>> st = posix.stat('/wrkdirs/usr/ports/lang/python315/work/stage/usr/local/bin/python3.15')
>>> hex(st.st_dev)
'0xffffffff8701ffb5'
>>> posix.major(st.st_dev)
-1
- The test_tempfile bombs out when trying to call
os.chflags(symlink, flags, follow_symlinks=False)withflags = stat.UF_IMMUTABLE | stat.UF_NOUNLINK; apparently thetmpfsfilesystem on FreeBSD does not support this and OSError 45 (EOPNOTSUPP) does not map to NotImplementedError in Python 3.15.0beta2. Not sure what's the proper fix here, one would be to map EOPNOTSUPP to a proper exception class, the other would be for the test to trap OSError and look at errno.
This is the test log failure in full verbose beauty:
0:01:38 load avg: 3.69 [1/2/1] test.test_os.test_posix failed (2 failures)
Re-running test.test_os.test_posix in verbose mode (matching: test_fs_holes, test_makedev)
test_fs_holes (test.test_os.test_posix.PosixTester.test_fs_holes) ... FAIL
test_makedev (test.test_os.test_posix.PosixTester.test_makedev) ... FAIL
======================================================================
FAIL: test_fs_holes (test.test_os.test_posix.PosixTester.test_fs_holes)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/wrkdirs/usr/ports/lang/python315/work/Python-3.15.0b2/Lib/test/test_os/test_posix.py", line 1532, in test_fs_holes
self.assertRaises(OSError, os.lseek, fno, size, os.SEEK_HOLE)
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: OSError not raised by lseek
======================================================================
FAIL: test_makedev (test.test_os.test_posix.PosixTester.test_makedev)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/wrkdirs/usr/ports/lang/python315/work/Python-3.15.0b2/Lib/test/test_os/test_posix.py", line 790, in test_makedev
self.assertGreaterEqual(major, 0)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
AssertionError: -1 not greater than or equal to 0
----------------------------------------------------------------------
Ran 2 tests in 0.003s
FAILED (failures=2)
test test.test_os.test_posix failed
0:01:38 load avg: 3.69 [2/2/2] test_tempfile failed (5 errors)
Re-running test_tempfile in verbose mode (matching: test_cleanup_with_symlink_flags, test_cleanup_with_symlink_flags, test_cleanup_with_symlink_flags, test_cleanup_with_symlink_flags, test_flags)
test_cleanup_with_symlink_flags (test.test_tempfile.TestTemporaryDirectory.test_cleanup_with_symlink_flags) ...
test_cleanup_with_symlink_flags (test.test_tempfile.TestTemporaryDirectory.test_cleanup_with_symlink_flags) [nonexisting file] ... ERROR
test_cleanup_with_symlink_flags (test.test_tempfile.TestTemporaryDirectory.test_cleanup_with_symlink_flags) [nonexisting dir] ... ERROR
test_cleanup_with_symlink_flags (test.test_tempfile.TestTemporaryDirectory.test_cleanup_with_symlink_flags) [existing file] ... ERROR
test_cleanup_with_symlink_flags (test.test_tempfile.TestTemporaryDirectory.test_cleanup_with_symlink_flags) [existing dir] ... ERROR
test_flags (test.test_tempfile.TestTemporaryDirectory.test_flags) ... ERROR
======================================================================
ERROR: test_cleanup_with_symlink_flags (test.test_tempfile.TestTemporaryDirectory.test_cleanup_with_symlink_flags) [nonexisting file]
----------------------------------------------------------------------
Traceback (most recent call last):
File "/wrkdirs/usr/ports/lang/python315/work/Python-3.15.0b2/Lib/test/test_tempfile.py", line 1832, in test_cleanup_with_symlink_flags
test('nonexisting', target_is_directory=False)
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/wrkdirs/usr/ports/lang/python315/work/Python-3.15.0b2/Lib/test/test_tempfile.py", line 1820, in test
os.chflags(symlink, flags, follow_symlinks=False)
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 45] Operation not supported: '/tmp/test_python_wenwj7ax/yq6hd0lh/symlink'
======================================================================
ERROR: test_cleanup_with_symlink_flags (test.test_tempfile.TestTemporaryDirectory.test_cleanup_with_symlink_flags) [nonexisting dir]
----------------------------------------------------------------------
Traceback (most recent call last):
File "/wrkdirs/usr/ports/lang/python315/work/Python-3.15.0b2/Lib/test/test_tempfile.py", line 1834, in test_cleanup_with_symlink_flags
test('nonexisting', target_is_directory=True)
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/wrkdirs/usr/ports/lang/python315/work/Python-3.15.0b2/Lib/test/test_tempfile.py", line 1820, in test
os.chflags(symlink, flags, follow_symlinks=False)
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 45] Operation not supported: '/tmp/test_python_wenwj7ax/eussrknv/symlink'
======================================================================
ERROR: test_cleanup_with_symlink_flags (test.test_tempfile.TestTemporaryDirectory.test_cleanup_with_symlink_flags) [existing file]
----------------------------------------------------------------------
Traceback (most recent call last):
File "/wrkdirs/usr/ports/lang/python315/work/Python-3.15.0b2/Lib/test/test_tempfile.py", line 1837, in test_cleanup_with_symlink_flags
os.chflags(file1, flags)
~~~~~~~~~~^^^^^^^^^^^^^^
OSError: [Errno 45] Operation not supported: '/tmp/test_python_wenwj7ax/fm9ia__3/file1'
======================================================================
ERROR: test_cleanup_with_symlink_flags (test.test_tempfile.TestTemporaryDirectory.test_cleanup_with_symlink_flags) [existing dir]
----------------------------------------------------------------------
Traceback (most recent call last):
File "/wrkdirs/usr/ports/lang/python315/work/Python-3.15.0b2/Lib/test/test_tempfile.py", line 1844, in test_cleanup_with_symlink_flags
os.chflags(dir1, flags)
~~~~~~~~~~^^^^^^^^^^^^^
OSError: [Errno 45] Operation not supported: '/tmp/test_python_wenwj7ax/fm9ia__3/dir1'
======================================================================
ERROR: test_flags (test.test_tempfile.TestTemporaryDirectory.test_flags)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/wrkdirs/usr/ports/lang/python315/work/Python-3.15.0b2/Lib/test/test_tempfile.py", line 2048, in test_flags
os.chflags(os.path.join(root, name), flags)
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 45] Operation not supported: '/tmp/test_python_wenwj7ax/br23xb02/dir0/dir0/dir0/test1.txt'
----------------------------------------------------------------------
Ran 2 tests in 0.007s
FAILED (errors=5)
test test_tempfile failed
2 tests failed again:
test.test_os.test_posix test_tempfile
== Tests result: FAILURE then FAILURE ==
[...]
2 tests failed:
test.test_os.test_posix test_tempfile
465 tests OK.
Total duration: 1 min 38 sec
Total tests: run=49,593 failures=4 skipped=2,781
Total test files: run=498/499 failed=2 skipped=29 resource_denied=3 rerun=2
Result: FAILURE then FAILURE
CPython versions tested on:
3.15
Operating systems tested on:
Other
貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
研究方向
從 Lib/test/test_os/test_posix.py 開始,尤其查看 test_fs_holes 和 test_makedev,以及 Lib/test/test_tempfile.py 中 test_cleanup_with_symlink_flags 和 test_flags 附近的內容。在 FreeBSD tmpfs 上重現這些失敗,然後檢查相關的 os.chflags 和 POSIX 行為,再決定是否需要調整測試或例外處理。完成的標準是受影響的測試能夠通過,同時不削弱受支援平台上的行為。
由索引模型根據 Issue 內容生成。
評估
- 技術堆疊
- python
- 領域
- operating-systems, testing-qa
- Issue 類型
- 缺陷
- 難度
- 4/5
- 預估耗時
- 3-5 天
- 活躍度
- 冷清
- 描述清晰度
- 基本清楚
- 新手友好度
- 48/100