mirror of
https://github.com/internetarchive/brozzler.git
synced 2025-06-06 22:29:11 -04:00
even more, better failing tests for thread_raise
This commit is contained in:
parent
d2525e2e87
commit
d514eaec15
2 changed files with 73 additions and 46 deletions
2
setup.py
2
setup.py
|
@ -32,7 +32,7 @@ def find_package_data(package):
|
||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name='brozzler',
|
name='brozzler',
|
||||||
version='1.1b11.dev246',
|
version='1.1b11.dev247',
|
||||||
description='Distributed web crawling with browsers',
|
description='Distributed web crawling with browsers',
|
||||||
url='https://github.com/internetarchive/brozzler',
|
url='https://github.com/internetarchive/brozzler',
|
||||||
author='Noah Levitt',
|
author='Noah Levitt',
|
||||||
|
|
|
@ -192,31 +192,12 @@ def test_start_stop_backwards_compat():
|
||||||
assert not 'started' in job
|
assert not 'started' in job
|
||||||
assert not 'finished' in job
|
assert not 'finished' in job
|
||||||
|
|
||||||
def test_thread_raise():
|
class Exception1(Exception):
|
||||||
thread_caught_exception = None
|
pass
|
||||||
|
class Exception2(Exception):
|
||||||
class Exception1(Exception):
|
pass
|
||||||
pass
|
|
||||||
class Exception2(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def accept_immediately():
|
|
||||||
try:
|
|
||||||
with brozzler.thread_accept_exceptions():
|
|
||||||
brozzler.sleep(2)
|
|
||||||
except Exception as e:
|
|
||||||
nonlocal thread_caught_exception
|
|
||||||
thread_caught_exception = e
|
|
||||||
|
|
||||||
def accept_eventually():
|
|
||||||
try:
|
|
||||||
brozzler.sleep(2)
|
|
||||||
with brozzler.thread_accept_exceptions():
|
|
||||||
pass
|
|
||||||
except Exception as e:
|
|
||||||
nonlocal thread_caught_exception
|
|
||||||
thread_caught_exception = e
|
|
||||||
|
|
||||||
|
def test_thread_raise_not_accept():
|
||||||
def never_accept():
|
def never_accept():
|
||||||
try:
|
try:
|
||||||
brozzler.sleep(2)
|
brozzler.sleep(2)
|
||||||
|
@ -224,42 +205,50 @@ def test_thread_raise():
|
||||||
nonlocal thread_caught_exception
|
nonlocal thread_caught_exception
|
||||||
thread_caught_exception = e
|
thread_caught_exception = e
|
||||||
|
|
||||||
def delay_context_exit():
|
|
||||||
try:
|
|
||||||
with brozzler.thread_accept_exceptions() as gate:
|
|
||||||
logging.info('gate=%s', gate)
|
|
||||||
orig_exit = gate.__exit__
|
|
||||||
import traceback
|
|
||||||
gate.__exit__ = lambda et, ev, t: (
|
|
||||||
logging.info('fake exit'), traceback.print_stack(),
|
|
||||||
brozzler.sleep(2), orig_exit(et, ev, t))
|
|
||||||
try:
|
|
||||||
brozzler.sleep(2)
|
|
||||||
except Exception as e:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
nonlocal thread_caught_exception
|
|
||||||
thread_caught_exception = e
|
|
||||||
|
|
||||||
# test that thread_raise does not raise exception in a thread that has no
|
# test that thread_raise does not raise exception in a thread that has no
|
||||||
# `with thread_exception_gate()` block
|
# `with thread_exception_gate()` block
|
||||||
thread_caught_exception = None
|
thread_caught_exception = None
|
||||||
th = threading.Thread(target=never_accept)
|
th = threading.Thread(target=never_accept)
|
||||||
th.start()
|
th.start()
|
||||||
brozzler.thread_raise(th, Exception)
|
brozzler.thread_raise(th, Exception1)
|
||||||
th.join()
|
th.join()
|
||||||
assert thread_caught_exception is None
|
assert thread_caught_exception is None
|
||||||
|
|
||||||
|
def test_thread_raise_immediate():
|
||||||
|
def accept_immediately():
|
||||||
|
try:
|
||||||
|
with brozzler.thread_accept_exceptions():
|
||||||
|
brozzler.sleep(2)
|
||||||
|
except Exception as e:
|
||||||
|
nonlocal thread_caught_exception
|
||||||
|
thread_caught_exception = e
|
||||||
|
|
||||||
# test immediate exception raise
|
# test immediate exception raise
|
||||||
thread_caught_exception = None
|
thread_caught_exception = None
|
||||||
th = threading.Thread(target=accept_immediately)
|
th = threading.Thread(target=accept_immediately)
|
||||||
th.start()
|
th.start()
|
||||||
brozzler.thread_raise(th, Exception)
|
brozzler.thread_raise(th, Exception1)
|
||||||
start = time.time()
|
start = time.time()
|
||||||
th.join()
|
th.join()
|
||||||
assert thread_caught_exception
|
assert thread_caught_exception
|
||||||
|
assert isinstance(thread_caught_exception, Exception1)
|
||||||
assert time.time() - start < 1.0
|
assert time.time() - start < 1.0
|
||||||
|
|
||||||
|
def test_thread_raise_safe_exit():
|
||||||
|
def delay_context_exit():
|
||||||
|
gate = brozzler.thread_accept_exceptions()
|
||||||
|
orig_exit = type(gate).__exit__
|
||||||
|
try:
|
||||||
|
type(gate).__exit__ = lambda self, et, ev, t: (
|
||||||
|
brozzler.sleep(2), orig_exit(self, et, ev, t), False)[-1]
|
||||||
|
with brozzler.thread_accept_exceptions() as gate:
|
||||||
|
brozzler.sleep(2)
|
||||||
|
except Exception as e:
|
||||||
|
nonlocal thread_caught_exception
|
||||||
|
thread_caught_exception = e
|
||||||
|
finally:
|
||||||
|
type(gate).__exit__ = orig_exit
|
||||||
|
|
||||||
# test that a second thread_raise() doesn't result in an exception in
|
# test that a second thread_raise() doesn't result in an exception in
|
||||||
# ThreadExceptionGate.__exit__
|
# ThreadExceptionGate.__exit__
|
||||||
thread_caught_exception = None
|
thread_caught_exception = None
|
||||||
|
@ -273,13 +262,51 @@ def test_thread_raise():
|
||||||
assert thread_caught_exception
|
assert thread_caught_exception
|
||||||
assert isinstance(thread_caught_exception, Exception1)
|
assert isinstance(thread_caught_exception, Exception1)
|
||||||
|
|
||||||
|
def test_thread_raise_pending_exception():
|
||||||
|
def accept_eventually():
|
||||||
|
try:
|
||||||
|
brozzler.sleep(2)
|
||||||
|
with brozzler.thread_accept_exceptions():
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
nonlocal thread_caught_exception
|
||||||
|
thread_caught_exception = e
|
||||||
|
|
||||||
# test exception that has to wait for `with thread_exception_gate()` block
|
# test exception that has to wait for `with thread_exception_gate()` block
|
||||||
thread_caught_exception = None
|
thread_caught_exception = None
|
||||||
th = threading.Thread(target=accept_eventually)
|
th = threading.Thread(target=accept_eventually)
|
||||||
th.start()
|
th.start()
|
||||||
brozzler.thread_raise(th, Exception)
|
brozzler.thread_raise(th, Exception1)
|
||||||
start = time.time()
|
start = time.time()
|
||||||
th.join()
|
th.join()
|
||||||
assert thread_caught_exception
|
assert isinstance(thread_caught_exception, Exception1)
|
||||||
assert time.time() - start > 1.0
|
assert time.time() - start > 1.0
|
||||||
|
|
||||||
|
def test_thread_raise_second_with_block():
|
||||||
|
def two_with_blocks():
|
||||||
|
try:
|
||||||
|
with brozzler.thread_accept_exceptions():
|
||||||
|
time.sleep(2)
|
||||||
|
return # test fails
|
||||||
|
except Exception1 as e:
|
||||||
|
pass
|
||||||
|
except:
|
||||||
|
return # fail test
|
||||||
|
|
||||||
|
try:
|
||||||
|
with brozzler.thread_accept_exceptions():
|
||||||
|
brozzler.sleep(2)
|
||||||
|
except Exception as e:
|
||||||
|
nonlocal thread_caught_exception
|
||||||
|
thread_caught_exception = e
|
||||||
|
|
||||||
|
# test that second `with` block gets second exception raised during first
|
||||||
|
# `with` block
|
||||||
|
thread_caught_exception = None
|
||||||
|
th = threading.Thread(target=two_with_blocks)
|
||||||
|
th.start()
|
||||||
|
brozzler.thread_raise(th, Exception1)
|
||||||
|
brozzler.thread_raise(th, Exception2)
|
||||||
|
th.join()
|
||||||
|
assert isinstance(thread_caught_exception, Exception2)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue