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

handling memory error in timeout utility #21

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
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
43 changes: 26 additions & 17 deletions codewars_test/test_framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def assert_approx_equals(
expect(abs((actual - expected) / div) < margin, message, allow_raise)



'''
Usage:
@describe('describe text')
Expand All @@ -94,7 +95,6 @@ def it1():
# some test cases...
'''


def _timed_block_factory(opening_text):
from timeit import default_timer as timer
from traceback import format_exception
Expand Down Expand Up @@ -126,28 +126,37 @@ def wrapper(func):
it = _timed_block_factory('IT')


'''
Timeout utility
Usage:
@timeout(sec)
def some_tests():
any code block...
Note: Timeout value can be a float.
'''


def timeout(sec):
def timeout(sec, user_msg=""):
def wrapper(func):
from multiprocessing import Process
msg = 'Should not throw any exceptions inside timeout'
from multiprocessing import Process, Value

def wrapped():
expect_no_error(msg, func)
process = Process(target=wrapped)
def wrapped(finished):
try:
func()
finished.value = 1.0
except BaseException as e:
finished.value = 1.0
fail("Should not throw any exceptions inside timeout: {}".format(repr(e)))

finished = Value('d',0.0)
# needed to know if the process crashed without any "feedback" and before any
# assertion has been done in the wrapped function or the wrapper (happens if
# the heap memory explodes)

process = Process(target=wrapped, args=(finished,))
process.start()
process.join(sec)

if process.is_alive():
fail('Exceeded time limit of {:.3f} seconds'.format(sec))
msg = 'Exceeded time limit of {:.3f} seconds'.format(sec)
if user_msg:
msg += ': ' + user_msg
fail(msg)
process.terminate()
process.join()
elif not finished.value:
fail('Something went wrong: the process running the function crashed without feedback (probably saturating the available memory)')

return wrapper
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

<DESCRIBE::>group 1

<FAILED::>Didn't pass

<COMPLETEDIN::>30.41
8 changes: 8 additions & 0 deletions tests/fixtures/timeout_failing_inner_test_assertion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import codewars_test as test


@test.describe("group 1")
def group_1():
@test.timeout(0.01)
def test_1():
test.fail("Didn't pass")
8 changes: 8 additions & 0 deletions tests/fixtures/timeout_failing_memory_crash.expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

<DESCRIBE::>group 1

<IT::>check memory crash

<FAILED::>Something went wrong: the process running the function crashed without feedback (probably saturating the available memory)

<COMPLETEDIN::>30.41
32 changes: 32 additions & 0 deletions tests/fixtures/timeout_failing_memory_crash.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
def group_1():
@test.timeout(0.01)
def test_1():
x = 0
while x < 10 ** 9:
x += 1
while True:
pass
test.pass_()
8 changes: 8 additions & 0 deletions tests/fixtures/timeout_failing_user_raise_error.expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

<DESCRIBE::>group 1

<IT::>it 1

<FAILED::>Should not throw any exceptions inside timeout: KeyError()

<COMPLETEDIN::>30.41
11 changes: 11 additions & 0 deletions tests/fixtures/timeout_failing_user_raise_error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import codewars_test as test


@test.describe("group 1")
def group_1():
@test.it("it 1")
def group_1():
@test.timeout(0.2)
def test_1():
raise KeyError()
test.pass_()
6 changes: 6 additions & 0 deletions tests/fixtures/timeout_failing_with_user_message.expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

<DESCRIBE::>group 1

<FAILED::>Exceeded time limit of 0.010 seconds: nope...

<COMPLETEDIN::>30.41
10 changes: 10 additions & 0 deletions tests/fixtures/timeout_failing_with_user_message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import codewars_test as test


@test.describe("group 1")
def group_1():
@test.timeout(0.01, "nope...")
def test_1():
while True:
pass
test.pass_()
2 changes: 0 additions & 2 deletions tests/fixtures/timeout_passing.expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,4 @@

<PASSED::>Test Passed

<PASSED::>Test Passed

<COMPLETEDIN::>17.19