mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
* Unskip passing flaky CPython tests Remove RUSTPYTHON skip overlays after Linux release repeats passed for enum, threading, logging, subprocess, socket, int, re, strtod, and regrtest cases. Assisted-by: Grok:4.6 * Fix fork-child SIGSEGV and yield-from throw args Forget JoinHandle of threads that did not survive fork instead of dropping them. Zero-reinit the import lock and condvars in the child rather than unlock/notify. Resume the world if os.fork() fails. Call a yield-from subiterator throw() without None fillers so a 1-arg throw stays 1-arg. Drop the stale Windows expectedFailure on logging queue config and unskip test_reinit_tls_after_fork plus the asyncio local_addr family test. Assisted-by: Grok:4.6 * Restore import lock depth after fork; add WASI clock info Zeroing IMP_LOCK in the child discarded its recursion count, so imp.release_lock() raised and test_fork1 exited 1. Re-acquire the saved depth, then drop the extra pre-fork hold. Expose time.get_clock_info on WASI via clock_getres so test_int Stopwatch can run. Unskip lock_tests test_acquire_contended and test_thread_leak. Assisted-by: Grok:4.6 * Honor chmod follow_symlinks=False via fchmodat Linux chmod followed the symlink, so dangling links raised FileNotFoundError instead of NotImplementedError. Use fchmodat with AT_SYMLINK_NOFOLLOW and map ENOTSUP to NotImplementedError. Unskip httpservers truncated Content-Length (CPython already skips as root) and tempfile symlink-mode cleanup on Linux. Assisted-by: Grok:4.6 * Unskip httplib local bad-hostname HTTPS test The skip was leftover. With default ssl-rustls the test passes under -W error on Linux. Assisted-by: Grok:4.6 * Fix list cmp deadlock, wasm digit overflow, REPL prompt Do not hold list/deque locks across item comparison callbacks. Compute int-to-str digit bounds in u64 so the check cannot wrap on wasm32. Snapshot set contents when list.extend copies a set. For a non-TTY stdin, write the REPL prompt to stderr and read lines from stdin. Flush stdout/stderr after each interactive command. Set sys.ps1/ps2 to ">>> " and "... ". Unskip list mutation compares, asyncio all_tasks race, importlib deadlock/parallel/circular-import tests, and REPL stdout flush. Assisted-by: Grok:4.6 * Avoid unnecessary u64 cast in int-to-str digit check bits() is already u64, so `bits as u64` fails clippy unnecessary_cast under -Dwarnings. Assisted-by: Grok:4.6
166 lines
4.9 KiB
Python
Vendored
166 lines
4.9 KiB
Python
Vendored
from test.test_importlib import util as test_util
|
|
|
|
init = test_util.import_importlib('importlib')
|
|
|
|
import sys
|
|
import threading
|
|
import unittest
|
|
import weakref
|
|
|
|
from test import support
|
|
from test.support import threading_helper
|
|
from test import lock_tests
|
|
|
|
|
|
threading_helper.requires_working_threading(module=True)
|
|
|
|
|
|
class ModuleLockAsRLockTests:
|
|
locktype = classmethod(lambda cls: cls.LockType("some_lock"))
|
|
|
|
# _is_owned() unsupported
|
|
test__is_owned = None
|
|
# acquire(blocking=False) unsupported
|
|
test_try_acquire = None
|
|
test_try_acquire_contended = None
|
|
# `with` unsupported
|
|
test_with = None
|
|
# acquire(timeout=...) unsupported
|
|
test_timeout = None
|
|
# _release_save() unsupported
|
|
test_release_save_unacquired = None
|
|
# _recursion_count() unsupported
|
|
test_recursion_count = None
|
|
# lock status in repr unsupported
|
|
test_repr = None
|
|
test_locked_repr = None
|
|
test_repr_count = None
|
|
|
|
def tearDown(self):
|
|
for splitinit in init.values():
|
|
splitinit._bootstrap._blocking_on.clear()
|
|
|
|
|
|
LOCK_TYPES = {kind: splitinit._bootstrap._ModuleLock
|
|
for kind, splitinit in init.items()}
|
|
|
|
(Frozen_ModuleLockAsRLockTests,
|
|
Source_ModuleLockAsRLockTests
|
|
) = test_util.test_both(ModuleLockAsRLockTests, lock_tests.RLockTests,
|
|
LockType=LOCK_TYPES)
|
|
|
|
|
|
class DeadlockAvoidanceTests:
|
|
|
|
def setUp(self):
|
|
try:
|
|
self.old_switchinterval = sys.getswitchinterval()
|
|
support.setswitchinterval(0.000001)
|
|
except AttributeError:
|
|
self.old_switchinterval = None
|
|
|
|
def tearDown(self):
|
|
if self.old_switchinterval is not None:
|
|
sys.setswitchinterval(self.old_switchinterval)
|
|
|
|
def run_deadlock_avoidance_test(self, create_deadlock):
|
|
NLOCKS = 10
|
|
locks = [self.LockType(str(i)) for i in range(NLOCKS)]
|
|
pairs = [(locks[i], locks[(i+1)%NLOCKS]) for i in range(NLOCKS)]
|
|
if create_deadlock:
|
|
NTHREADS = NLOCKS
|
|
else:
|
|
NTHREADS = NLOCKS - 1
|
|
barrier = threading.Barrier(NTHREADS)
|
|
results = []
|
|
|
|
def _acquire(lock):
|
|
"""Try to acquire the lock. Return True on success,
|
|
False on deadlock."""
|
|
try:
|
|
lock.acquire()
|
|
except self.DeadlockError:
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
def f():
|
|
a, b = pairs.pop()
|
|
ra = _acquire(a)
|
|
barrier.wait()
|
|
rb = _acquire(b)
|
|
results.append((ra, rb))
|
|
if rb:
|
|
b.release()
|
|
if ra:
|
|
a.release()
|
|
with lock_tests.Bunch(f, NTHREADS):
|
|
pass
|
|
self.assertEqual(len(results), NTHREADS)
|
|
return results
|
|
|
|
def test_deadlock(self):
|
|
results = self.run_deadlock_avoidance_test(True)
|
|
# At least one of the threads detected a potential deadlock on its
|
|
# second acquire() call. It may be several of them, because the
|
|
# deadlock avoidance mechanism is conservative.
|
|
nb_deadlocks = results.count((True, False))
|
|
self.assertGreaterEqual(nb_deadlocks, 1)
|
|
self.assertEqual(results.count((True, True)), len(results) - nb_deadlocks)
|
|
|
|
def test_no_deadlock(self):
|
|
results = self.run_deadlock_avoidance_test(False)
|
|
self.assertEqual(results.count((True, False)), 0)
|
|
self.assertEqual(results.count((True, True)), len(results))
|
|
|
|
|
|
DEADLOCK_ERRORS = {kind: splitinit._bootstrap._DeadlockError
|
|
for kind, splitinit in init.items()}
|
|
|
|
(Frozen_DeadlockAvoidanceTests,
|
|
Source_DeadlockAvoidanceTests
|
|
) = test_util.test_both(DeadlockAvoidanceTests,
|
|
LockType=LOCK_TYPES,
|
|
DeadlockError=DEADLOCK_ERRORS)
|
|
|
|
|
|
class LifetimeTests:
|
|
|
|
@property
|
|
def bootstrap(self):
|
|
return self.init._bootstrap
|
|
|
|
def test_lock_lifetime(self):
|
|
name = "xyzzy"
|
|
self.assertNotIn(name, self.bootstrap._module_locks)
|
|
lock = self.bootstrap._get_module_lock(name)
|
|
self.assertIn(name, self.bootstrap._module_locks)
|
|
wr = weakref.ref(lock)
|
|
del lock
|
|
support.gc_collect()
|
|
self.assertNotIn(name, self.bootstrap._module_locks)
|
|
self.assertIsNone(wr())
|
|
|
|
def test_all_locks(self):
|
|
support.gc_collect()
|
|
self.assertEqual(0, len(self.bootstrap._module_locks),
|
|
self.bootstrap._module_locks)
|
|
|
|
|
|
(Frozen_LifetimeTests,
|
|
Source_LifetimeTests
|
|
) = test_util.test_both(LifetimeTests, init=init)
|
|
|
|
# TODO: RUSTPYTHON; dead weakref module locks not cleaned up in frozen bootstrap
|
|
Frozen_LifetimeTests.test_all_locks = unittest.skip("TODO: RUSTPYTHON")(
|
|
Frozen_LifetimeTests.test_all_locks
|
|
)
|
|
|
|
def setUpModule():
|
|
thread_info = threading_helper.threading_setup()
|
|
unittest.addModuleCleanup(threading_helper.threading_cleanup, *thread_info)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|