Skip to content

Commit e4439c5

Browse files
committed
test: add tests for new task result and exception behavior
1 parent 0fef362 commit e4439c5

10 files changed

+341
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Test the Task.done() method
2+
3+
try:
4+
import asyncio
5+
except ImportError:
6+
print("SKIP")
7+
raise SystemExit
8+
9+
10+
async def task(t, exc=None):
11+
if t >= 0:
12+
await asyncio.sleep(t)
13+
if exc:
14+
raise exc
15+
16+
17+
async def main():
18+
# Tasks that aren't done only execute done callback after finishing
19+
print("=" * 10)
20+
t = asyncio.create_task(task(-1))
21+
t.add_done_callback(lambda: print("done"))
22+
print("Waiting for task to complete")
23+
await asyncio.sleep(0)
24+
print("Task has completed")
25+
26+
# Task that are done run the callback immediately
27+
print("=" * 10)
28+
t = asyncio.create_task(task(-1))
29+
await asyncio.sleep(0)
30+
print("Task has completed")
31+
t.add_done_callback(lambda: print("done"))
32+
print("Callback Added")
33+
34+
# Task that starts, runs and finishes without an exception should return None
35+
print("=" * 10)
36+
t = asyncio.create_task(task(0.01))
37+
t.add_done_callback(lambda: print("done"))
38+
try:
39+
t.add_done_callback(lambda: print("done"))
40+
except RuntimeError as e:
41+
print("Second call to add_done_callback emits error:", repr(e))
42+
43+
# Task that raises immediately should still run done callback
44+
print("=" * 10)
45+
t = asyncio.create_task(task(-1, ValueError))
46+
t.add_done_callback(lambda: print("done"))
47+
await asyncio.sleep(0)
48+
49+
50+
asyncio.run(main())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
==========
2+
Waiting for task to complete
3+
done
4+
Task has completed
5+
==========
6+
Task has completed
7+
done
8+
Callback added
9+
==========
10+
Second call to add_done_callback emits error: Tasks only support one done callback.
11+
==========
12+
Waiting for task to complete
13+
done
14+
Exception handled
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Test cancelling a task
2+
3+
try:
4+
import asyncio
5+
except ImportError:
6+
print("SKIP")
7+
raise SystemExit
8+
9+
10+
async def task(t):
11+
await asyncio.sleep(t)
12+
13+
14+
async def main():
15+
# Cancel task immediately doesn't mark the task as cancelled
16+
print("=" * 10)
17+
t = asyncio.create_task(task(2))
18+
t.cancel()
19+
print("Expecting task to not be cancelled because it is not done:", t.cancelled())
20+
21+
# Cancel task immediately and wait for cancellation to complete
22+
print("=" * 10)
23+
t = asyncio.create_task(task(2))
24+
t.cancel()
25+
await asyncio.sleep(0)
26+
print("Expecting Task to be Cancelled:", t.cancelled())
27+
28+
# Cancel task and wait for cancellation to complete
29+
print("=" * 10)
30+
t = asyncio.create_task(task(2))
31+
await asyncio.sleep(0.01)
32+
t.cancel()
33+
await asyncio.sleep(0)
34+
print("Expecting Task to be Cancelled:", t.cancelled())
35+
36+
# Cancel task multiple times after it has started
37+
print("=" * 10)
38+
t = asyncio.create_task(task(2))
39+
await asyncio.sleep(0.01)
40+
for _ in range(4):
41+
t.cancel()
42+
await asyncio.sleep(0.01)
43+
44+
print("Expecting Task to be Cancelled:", t.cancelled())
45+
46+
# Cancel task after it has finished
47+
print("=" * 10)
48+
t = asyncio.create_task(task(0.01))
49+
await asyncio.sleep(0.05)
50+
t.cancel()
51+
print("Expecting task to not be Cancelled:", t.cancelled())
52+
53+
54+
asyncio.run(main())
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
==========
2+
Expecting task to not be cancelled because it is not done: False
3+
==========
4+
Expecting Task to be Cancelled: True
5+
==========
6+
Expecting Task to be Cancelled: True
7+
==========
8+
Expecting Task to be Cancelled: True
9+
==========
10+
Expecting task to not be Cancelled: False
+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Test the Task.done() method
2+
3+
try:
4+
import asyncio
5+
except ImportError:
6+
print("SKIP")
7+
raise SystemExit
8+
9+
10+
async def task(t, exc=None):
11+
if t >= 0:
12+
await asyncio.sleep(t)
13+
if exc:
14+
raise exc
15+
16+
17+
async def main():
18+
# Task that is not done yet raises an InvalidStateError
19+
print("=" * 10)
20+
t = asyncio.create_task(task(1))
21+
await asyncio.sleep(0)
22+
try:
23+
t.exception()
24+
assert False, "Should not get here"
25+
except Exception as e:
26+
print("Tasks that aren't done yet raise an InvalidStateError:", repr(e))
27+
28+
# Task that is cancelled raises CancelledError
29+
print("=" * 10)
30+
t = asyncio.create_task(task(1))
31+
t.cancel()
32+
await asyncio.sleep(0)
33+
try:
34+
print(repr(t.exception()))
35+
print(t.cancelled())
36+
assert False, "Should not get here"
37+
except asyncio.CancelledError as e:
38+
print("Cancelled tasks cannot retrieve exception:", repr(e))
39+
40+
# Task that starts, runs and finishes without an exception should return None
41+
print("=" * 10)
42+
t = asyncio.create_task(task(0.01))
43+
await t
44+
print("None when no exception:", t.exception())
45+
46+
# Task that raises immediately should return that exception
47+
print("=" * 10)
48+
t = asyncio.create_task(task(-1, ValueError))
49+
try:
50+
await t
51+
assert False, "Should not get here"
52+
except ValueError as e:
53+
pass
54+
print("Returned Exception:", repr(t.exception()))
55+
56+
57+
asyncio.run(main())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
==========
2+
Tasks that aren't done yet raise an InvalidStateError: InvalidStateError('Exception is not set.',)
3+
==========
4+
Cancelled tasks cannot retrieve exception: CancelledError()
5+
==========
6+
None when no exception: None
7+
==========
8+
Returned Exception: ValueError()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Test the Task.done() method
2+
3+
try:
4+
import asyncio
5+
except ImportError:
6+
print("SKIP")
7+
raise SystemExit
8+
9+
10+
async def task(t, exc=None):
11+
if t >= 0:
12+
await asyncio.sleep(t)
13+
if exc:
14+
raise exc
15+
16+
17+
def done_callback():
18+
print("done")
19+
20+
21+
def done_callback_2():
22+
print("done 2")
23+
24+
25+
async def main():
26+
# Removing a callback returns 0 when no callbacks have been set
27+
print("=" * 10)
28+
t = asyncio.create_task(task(1))
29+
print("Returns 0 when no done callback has been set:", t.remove_done_callback(done_callback))
30+
31+
# Done callback removal only works once
32+
print("=" * 10)
33+
t = asyncio.create_task(task(1))
34+
t.add_done_callback(done_callback)
35+
print(
36+
"Returns 1 when a callback matches and is removed:", t.remove_done_callback(done_callback)
37+
)
38+
print(
39+
"Returns 0 on second attempt to remove the callback:",
40+
t.remove_done_callback(done_callback),
41+
)
42+
43+
# Only removes done callback when match
44+
print("=" * 10)
45+
t = asyncio.create_task(task(0.01))
46+
t.add_done_callback(done_callback)
47+
print("Returns 0 when done callbacks don't match:", t.remove_done_callback(done_callback_2))
48+
49+
# A removed done callback does not execute
50+
print("=" * 10)
51+
t = asyncio.create_task(task(-1))
52+
t.add_done_callback(done_callback)
53+
t.remove_done_callback(done_callback)
54+
print("Waiting for task to complete")
55+
await t
56+
print("Task completed")
57+
58+
59+
asyncio.run(main())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
==========
2+
Returns 0 when no done callback has been set: 0
3+
==========
4+
Returns 1 when a callback matches and is removed: 1
5+
Returns 0 on second attempt to remove the callback: 0
6+
==========
7+
Returns 0 when done callbacks don't match: 0
8+
==========
9+
Waiting for task to complete
10+
Task completed

tests/extmod/asyncio_task_result.py

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Test the Task.done() method
2+
3+
try:
4+
import asyncio
5+
except ImportError:
6+
print("SKIP")
7+
raise SystemExit
8+
9+
10+
async def task(t, exc=None, ret=None):
11+
if t >= 0:
12+
await asyncio.sleep(t)
13+
if exc:
14+
raise exc
15+
return ret
16+
17+
18+
async def main():
19+
# Task that is not done yet raises an InvalidStateError
20+
print("=" * 10)
21+
t = asyncio.create_task(task(1))
22+
await asyncio.sleep(0)
23+
try:
24+
t.result()
25+
assert False, "Should not get here"
26+
except Exception as e:
27+
print("InvalidStateError if still running:", repr(e))
28+
29+
# Task that is cancelled raises CancelledError
30+
print("=" * 10)
31+
t = asyncio.create_task(task(1))
32+
t.cancel()
33+
await asyncio.sleep(0)
34+
try:
35+
t.result()
36+
assert False, "Should not get here"
37+
except asyncio.CancelledError as e:
38+
print("CancelledError when retrieving result from cancelled task:", repr(e))
39+
40+
# Task that raises immediately should raise that exception when calling result
41+
print("=" * 10)
42+
t = asyncio.create_task(task(-1, ValueError))
43+
try:
44+
await t
45+
assert False, "Should not get here"
46+
except ValueError as e:
47+
pass
48+
49+
try:
50+
t.result()
51+
assert False, "Should not get here"
52+
except ValueError as e:
53+
print("Error raised when result is attempted on task with error:", repr(e))
54+
55+
# Task that starts, runs and finishes without an exception or value should return None
56+
print("=" * 10)
57+
t = asyncio.create_task(task(0.01))
58+
await t
59+
print("Empty Result should be None:", t.result())
60+
assert t.result() is None
61+
62+
# Task that starts, runs and finishes without exception should return result
63+
print("=" * 10)
64+
t = asyncio.create_task(task(0.01, None, "hello world"))
65+
await t
66+
print("Happy path, result is returned:", t.result())
67+
68+
69+
asyncio.run(main())
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
==========
2+
InvalidStateError if still running: InvalidStateError('Result is not ready.',)
3+
==========
4+
CancelledError when retrieving result from cancelled task: CancelledError()
5+
==========
6+
Error raised when result is attempted on task with error: ValueError()
7+
==========
8+
Empty Result should be None: None
9+
==========
10+
Happy path, result is returned: hello world

0 commit comments

Comments
 (0)