summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2019-11-13 21:08:22 +1100
committerDamien George <damien.p.george@gmail.com>2020-03-26 01:25:45 +1100
commitc4935f30490d0446e16a51dbf7a6397b771cf804 (patch)
treeb095dd91914950939d4d0cdc10e7be3625fff00d
parent63b99443820f53afbdab5201044629d2bfecd73b (diff)
downloadmicropython-c4935f30490d0446e16a51dbf7a6397b771cf804.tar.gz
micropython-c4935f30490d0446e16a51dbf7a6397b771cf804.zip
tests/extmod: Add uasyncio tests.
All .exp files are included because they require CPython 3.8 which may not always be available.
-rw-r--r--tests/extmod/uasyncio_await_return.py26
-rw-r--r--tests/extmod/uasyncio_await_return.py.exp2
-rw-r--r--tests/extmod/uasyncio_basic.py43
-rw-r--r--tests/extmod/uasyncio_basic.py.exp5
-rw-r--r--tests/extmod/uasyncio_basic2.py24
-rw-r--r--tests/extmod/uasyncio_basic2.py.exp4
-rw-r--r--tests/extmod/uasyncio_cancel_fair.py37
-rw-r--r--tests/extmod/uasyncio_cancel_fair.py.exp24
-rw-r--r--tests/extmod/uasyncio_cancel_fair2.py37
-rw-r--r--tests/extmod/uasyncio_cancel_fair2.py.exp8
-rw-r--r--tests/extmod/uasyncio_cancel_self.py31
-rw-r--r--tests/extmod/uasyncio_cancel_self.py.exp2
-rw-r--r--tests/extmod/uasyncio_cancel_task.py85
-rw-r--r--tests/extmod/uasyncio_cancel_task.py.exp31
-rw-r--r--tests/extmod/uasyncio_event.py98
-rw-r--r--tests/extmod/uasyncio_event.py.exp33
-rw-r--r--tests/extmod/uasyncio_event_fair.py40
-rw-r--r--tests/extmod/uasyncio_event_fair.py.exp16
-rw-r--r--tests/extmod/uasyncio_exception.py60
-rw-r--r--tests/extmod/uasyncio_exception.py.exp7
-rw-r--r--tests/extmod/uasyncio_fair.py32
-rw-r--r--tests/extmod/uasyncio_fair.py.exp12
-rw-r--r--tests/extmod/uasyncio_gather.py49
-rw-r--r--tests/extmod/uasyncio_gather.py.exp10
-rw-r--r--tests/extmod/uasyncio_get_event_loop.py20
-rw-r--r--tests/extmod/uasyncio_heaplock.py46
-rw-r--r--tests/extmod/uasyncio_heaplock.py.exp11
-rw-r--r--tests/extmod/uasyncio_lock.py97
-rw-r--r--tests/extmod/uasyncio_lock.py.exp41
-rw-r--r--tests/extmod/uasyncio_lock_cancel.py55
-rw-r--r--tests/extmod/uasyncio_lock_cancel.py.exp11
-rw-r--r--tests/extmod/uasyncio_wait_for.py62
-rw-r--r--tests/extmod/uasyncio_wait_for.py.exp15
-rw-r--r--tests/extmod/uasyncio_wait_task.py77
-rw-r--r--tests/extmod/uasyncio_wait_task.py.exp10
35 files changed, 1161 insertions, 0 deletions
diff --git a/tests/extmod/uasyncio_await_return.py b/tests/extmod/uasyncio_await_return.py
new file mode 100644
index 0000000000..d375c9ea97
--- /dev/null
+++ b/tests/extmod/uasyncio_await_return.py
@@ -0,0 +1,26 @@
+# Test that tasks return their value correctly to the caller
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def foo():
+ return 42
+
+
+async def main():
+ # Call function directly via an await
+ print(await foo())
+
+ # Create a task and await on it
+ task = asyncio.create_task(foo())
+ print(await task)
+
+
+asyncio.run(main())
diff --git a/tests/extmod/uasyncio_await_return.py.exp b/tests/extmod/uasyncio_await_return.py.exp
new file mode 100644
index 0000000000..daaac9e303
--- /dev/null
+++ b/tests/extmod/uasyncio_await_return.py.exp
@@ -0,0 +1,2 @@
+42
+42
diff --git a/tests/extmod/uasyncio_basic.py b/tests/extmod/uasyncio_basic.py
new file mode 100644
index 0000000000..f6685fa674
--- /dev/null
+++ b/tests/extmod/uasyncio_basic.py
@@ -0,0 +1,43 @@
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+try:
+ import utime
+
+ ticks = utime.ticks_ms
+ ticks_diff = utime.ticks_diff
+except:
+ import time
+
+ ticks = lambda: int(time.time() * 1000)
+ ticks_diff = lambda t1, t0: t1 - t0
+
+
+async def delay_print(t, s):
+ await asyncio.sleep(t)
+ print(s)
+
+
+async def main():
+ print("start")
+
+ await asyncio.sleep(0.001)
+ print("after sleep")
+
+ t0 = ticks()
+ await delay_print(0.02, "short")
+ t1 = ticks()
+ await delay_print(0.04, "long")
+ t2 = ticks()
+
+ print("took {} {}".format(round(ticks_diff(t1, t0), -1), round(ticks_diff(t2, t1), -1)))
+
+
+asyncio.run(main())
diff --git a/tests/extmod/uasyncio_basic.py.exp b/tests/extmod/uasyncio_basic.py.exp
new file mode 100644
index 0000000000..447d05d5e0
--- /dev/null
+++ b/tests/extmod/uasyncio_basic.py.exp
@@ -0,0 +1,5 @@
+start
+after sleep
+short
+long
+took 20 40
diff --git a/tests/extmod/uasyncio_basic2.py b/tests/extmod/uasyncio_basic2.py
new file mode 100644
index 0000000000..a2167e48ee
--- /dev/null
+++ b/tests/extmod/uasyncio_basic2.py
@@ -0,0 +1,24 @@
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def forever():
+ print("forever start")
+ await asyncio.sleep(10)
+
+
+async def main():
+ print("main start")
+ asyncio.create_task(forever())
+ await asyncio.sleep(0.001)
+ print("main done")
+ return 42
+
+
+print(asyncio.run(main()))
diff --git a/tests/extmod/uasyncio_basic2.py.exp b/tests/extmod/uasyncio_basic2.py.exp
new file mode 100644
index 0000000000..3ca3521728
--- /dev/null
+++ b/tests/extmod/uasyncio_basic2.py.exp
@@ -0,0 +1,4 @@
+main start
+forever start
+main done
+42
diff --git a/tests/extmod/uasyncio_cancel_fair.py b/tests/extmod/uasyncio_cancel_fair.py
new file mode 100644
index 0000000000..9a7b35c161
--- /dev/null
+++ b/tests/extmod/uasyncio_cancel_fair.py
@@ -0,0 +1,37 @@
+# Test fairness of cancelling a task
+# That tasks which continuously cancel each other don't take over the scheduler
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def task(id, other):
+ for i in range(3):
+ try:
+ print("start", id)
+ await asyncio.sleep(0)
+ print("done", id)
+ except asyncio.CancelledError as er:
+ print("cancelled", id)
+ if other is not None:
+ print(id, "cancels", other)
+ tasks[other].cancel()
+
+
+async def main():
+ global tasks
+ tasks = [
+ asyncio.create_task(task(0, 1)),
+ asyncio.create_task(task(1, 0)),
+ asyncio.create_task(task(2, None)),
+ ]
+ await tasks[2]
+
+
+asyncio.run(main())
diff --git a/tests/extmod/uasyncio_cancel_fair.py.exp b/tests/extmod/uasyncio_cancel_fair.py.exp
new file mode 100644
index 0000000000..8f5da08e4c
--- /dev/null
+++ b/tests/extmod/uasyncio_cancel_fair.py.exp
@@ -0,0 +1,24 @@
+start 0
+start 1
+start 2
+done 0
+0 cancels 1
+start 0
+cancelled 1
+1 cancels 0
+start 1
+done 2
+start 2
+cancelled 0
+0 cancels 1
+start 0
+cancelled 1
+1 cancels 0
+start 1
+done 2
+start 2
+cancelled 0
+0 cancels 1
+cancelled 1
+1 cancels 0
+done 2
diff --git a/tests/extmod/uasyncio_cancel_fair2.py b/tests/extmod/uasyncio_cancel_fair2.py
new file mode 100644
index 0000000000..46e40f71b1
--- /dev/null
+++ b/tests/extmod/uasyncio_cancel_fair2.py
@@ -0,0 +1,37 @@
+# Test fairness of cancelling a task
+# That tasks which keeps being cancelled by multiple other tasks gets a chance to run
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def task_a():
+ try:
+ while True:
+ print("sleep a")
+ await asyncio.sleep(0)
+ except asyncio.CancelledError:
+ print("cancelled a")
+
+
+async def task_b(id, other):
+ while other.cancel():
+ print("sleep b", id)
+ await asyncio.sleep(0)
+ print("done b", id)
+
+
+async def main():
+ t = asyncio.create_task(task_a())
+ for i in range(3):
+ asyncio.create_task(task_b(i, t))
+ await t
+
+
+asyncio.run(main())
diff --git a/tests/extmod/uasyncio_cancel_fair2.py.exp b/tests/extmod/uasyncio_cancel_fair2.py.exp
new file mode 100644
index 0000000000..e9dd649b45
--- /dev/null
+++ b/tests/extmod/uasyncio_cancel_fair2.py.exp
@@ -0,0 +1,8 @@
+sleep a
+sleep b 0
+sleep b 1
+sleep b 2
+cancelled a
+done b 0
+done b 1
+done b 2
diff --git a/tests/extmod/uasyncio_cancel_self.py b/tests/extmod/uasyncio_cancel_self.py
new file mode 100644
index 0000000000..660ae66389
--- /dev/null
+++ b/tests/extmod/uasyncio_cancel_self.py
@@ -0,0 +1,31 @@
+# Test a task cancelling itself (currently unsupported)
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def task():
+ print("task start")
+ global_task.cancel()
+
+
+async def main():
+ global global_task
+ global_task = asyncio.create_task(task())
+ try:
+ await global_task
+ except asyncio.CancelledError:
+ print("main cancel")
+ print("main done")
+
+
+try:
+ asyncio.run(main())
+except RuntimeError as er:
+ print(er)
diff --git a/tests/extmod/uasyncio_cancel_self.py.exp b/tests/extmod/uasyncio_cancel_self.py.exp
new file mode 100644
index 0000000000..36fcb0a3f4
--- /dev/null
+++ b/tests/extmod/uasyncio_cancel_self.py.exp
@@ -0,0 +1,2 @@
+task start
+cannot cancel self
diff --git a/tests/extmod/uasyncio_cancel_task.py b/tests/extmod/uasyncio_cancel_task.py
new file mode 100644
index 0000000000..ec60d85545
--- /dev/null
+++ b/tests/extmod/uasyncio_cancel_task.py
@@ -0,0 +1,85 @@
+# Test cancelling a task
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def task(s, allow_cancel):
+ try:
+ print("task start")
+ await asyncio.sleep(s)
+ print("task done")
+ except asyncio.CancelledError as er:
+ print("task cancel")
+ if allow_cancel:
+ raise er
+
+
+async def task2(allow_cancel):
+ print("task 2")
+ try:
+ await asyncio.create_task(task(0.05, allow_cancel))
+ except asyncio.CancelledError as er:
+ print("task 2 cancel")
+ raise er
+ print("task 2 done")
+
+
+async def main():
+ # Cancel task immediately
+ t = asyncio.create_task(task(2, True))
+ print(t.cancel())
+
+ # Cancel task after it has started
+ t = asyncio.create_task(task(2, True))
+ await asyncio.sleep(0.01)
+ print(t.cancel())
+ print("main sleep")
+ await asyncio.sleep(0.01)
+
+ # Cancel task multiple times after it has started
+ t = asyncio.create_task(task(2, True))
+ await asyncio.sleep(0.01)
+ for _ in range(4):
+ print(t.cancel())
+ print("main sleep")
+ await asyncio.sleep(0.01)
+
+ # Await on a cancelled task
+ print("main wait")
+ try:
+ await t
+ except asyncio.CancelledError:
+ print("main got CancelledError")
+
+ # Cancel task after it has finished
+ t = asyncio.create_task(task(0.01, False))
+ await asyncio.sleep(0.05)
+ print(t.cancel())
+
+ # Nested: task2 waits on task, task2 is cancelled (should cancel task then task2)
+ print("----")
+ t = asyncio.create_task(task2(True))
+ await asyncio.sleep(0.01)
+ print("main cancel")
+ t.cancel()
+ print("main sleep")
+ await asyncio.sleep(0.1)
+
+ # Nested: task2 waits on task, task2 is cancelled but task doesn't allow it (task2 should continue)
+ print("----")
+ t = asyncio.create_task(task2(False))
+ await asyncio.sleep(0.01)
+ print("main cancel")
+ t.cancel()
+ print("main sleep")
+ await asyncio.sleep(0.1)
+
+
+asyncio.run(main())
diff --git a/tests/extmod/uasyncio_cancel_task.py.exp b/tests/extmod/uasyncio_cancel_task.py.exp
new file mode 100644
index 0000000000..031b94023f
--- /dev/null
+++ b/tests/extmod/uasyncio_cancel_task.py.exp
@@ -0,0 +1,31 @@
+True
+task start
+True
+main sleep
+task cancel
+task start
+True
+True
+True
+True
+main sleep
+task cancel
+main wait
+main got CancelledError
+task start
+task done
+False
+----
+task 2
+task start
+main cancel
+main sleep
+task cancel
+task 2 cancel
+----
+task 2
+task start
+main cancel
+main sleep
+task cancel
+task 2 done
diff --git a/tests/extmod/uasyncio_event.py b/tests/extmod/uasyncio_event.py
new file mode 100644
index 0000000000..fb8eb9ffa4
--- /dev/null
+++ b/tests/extmod/uasyncio_event.py
@@ -0,0 +1,98 @@
+# Test Event class
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def task(id, ev):
+ print("start", id)
+ print(await ev.wait())
+ print("end", id)
+
+
+async def task_delay_set(t, ev):
+ await asyncio.sleep(t)
+ print("set event")
+ ev.set()
+
+
+async def main():
+ ev = asyncio.Event()
+
+ # Set and clear without anything waiting, and test is_set()
+ print(ev.is_set())
+ ev.set()
+ print(ev.is_set())
+ ev.clear()
+ print(ev.is_set())
+
+ # Create 2 tasks waiting on the event
+ print("----")
+ asyncio.create_task(task(1, ev))
+ asyncio.create_task(task(2, ev))
+ print("yield")
+ await asyncio.sleep(0)
+ print("set event")
+ ev.set()
+ print("yield")
+ await asyncio.sleep(0)
+
+ # Create a task waiting on the already-set event
+ print("----")
+ asyncio.create_task(task(3, ev))
+ print("yield")
+ await asyncio.sleep(0)
+
+ # Clear event, start a task, then set event again
+ print("----")
+ print("clear event")
+ ev.clear()
+ asyncio.create_task(task(4, ev))
+ await asyncio.sleep(0)
+ print("set event")
+ ev.set()
+ await asyncio.sleep(0)
+
+ # Cancel a task waiting on an event (set event then cancel task)
+ print("----")
+ ev = asyncio.Event()
+ t = asyncio.create_task(task(5, ev))
+ await asyncio.sleep(0)
+ ev.set()
+ t.cancel()
+ await asyncio.sleep(0.1)
+
+ # Cancel a task waiting on an event (cancel task then set event)
+ print("----")
+ ev = asyncio.Event()
+ t = asyncio.create_task(task(6, ev))
+ await asyncio.sleep(0)
+ t.cancel()
+ ev.set()
+ await asyncio.sleep(0.1)
+
+ # Wait for an event that does get set in time
+ print("----")
+ ev.clear()
+ asyncio.create_task(task_delay_set(0.01, ev))
+ await asyncio.wait_for(ev.wait(), 0.1)
+ await asyncio.sleep(0)
+
+ # Wait for an event that doesn't get set in time
+ print("----")
+ ev.clear()
+ asyncio.create_task(task_delay_set(0.1, ev))
+ try:
+ await asyncio.wait_for(ev.wait(), 0.01)
+ except asyncio.TimeoutError:
+ print("TimeoutError")
+ await ev.wait()
+
+
+asyncio.run(main())
diff --git a/tests/extmod/uasyncio_event.py.exp b/tests/extmod/uasyncio_event.py.exp
new file mode 100644
index 0000000000..3188f291e5
--- /dev/null
+++ b/tests/extmod/uasyncio_event.py.exp
@@ -0,0 +1,33 @@
+False
+True
+False
+----
+yield
+start 1
+start 2
+set event
+yield
+True
+end 1
+True
+end 2
+----
+yield
+start 3
+True
+end 3
+----
+clear event
+start 4
+set event
+True
+end 4
+----
+start 5
+----
+start 6
+----
+set event
+----
+TimeoutError
+set event
diff --git a/tests/extmod/uasyncio_event_fair.py b/tests/extmod/uasyncio_event_fair.py
new file mode 100644
index 0000000000..37eca5faef
--- /dev/null
+++ b/tests/extmod/uasyncio_event_fair.py
@@ -0,0 +1,40 @@
+# Test fairness of Event.set()
+# That tasks which continuously wait on events don't take over the scheduler
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def task1(id):
+ for i in range(4):
+ print("sleep", id)
+ await asyncio.sleep(0)
+
+
+async def task2(id, ev):
+ for i in range(4):
+ ev.set()
+ ev.clear()
+ print("wait", id)
+ await ev.wait()
+
+
+async def main():
+ ev = asyncio.Event()
+ tasks = [
+ asyncio.create_task(task1(0)),
+ asyncio.create_task(task2(2, ev)),
+ asyncio.create_task(task1(1)),
+ asyncio.create_task(task2(3, ev)),
+ ]
+ await tasks[1]
+ ev.set()
+
+
+asyncio.run(main())
diff --git a/tests/extmod/uasyncio_event_fair.py.exp b/tests/extmod/uasyncio_event_fair.py.exp
new file mode 100644
index 0000000000..fe2e3d6e47
--- /dev/null
+++ b/tests/extmod/uasyncio_event_fair.py.exp
@@ -0,0 +1,16 @@
+sleep 0
+wait 2
+sleep 1
+wait 3
+sleep 0
+sleep 1
+wait 2
+sleep 0
+sleep 1
+wait 3
+sleep 0
+sleep 1
+wait 2
+wait 3
+wait 2
+wait 3
diff --git a/tests/extmod/uasyncio_exception.py b/tests/extmod/uasyncio_exception.py
new file mode 100644
index 0000000000..aae55d6320
--- /dev/null
+++ b/tests/extmod/uasyncio_exception.py
@@ -0,0 +1,60 @@
+# Test general exception handling
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+# main task raising an exception
+async def main():
+ print("main start")
+ raise ValueError(1)
+ print("main done")
+
+
+try:
+ asyncio.run(main())
+except ValueError as er:
+ print("ValueError", er.args[0])
+
+# sub-task raising an exception
+async def task():
+ print("task start")
+ raise ValueError(2)
+ print("task done")
+
+
+async def main():
+ print("main start")
+ t = asyncio.create_task(task())
+ await t
+ print("main done")
+
+
+try:
+ asyncio.run(main())
+except ValueError as er:
+ print("ValueError", er.args[0])
+
+# main task raising an exception with sub-task not yet scheduled
+# TODO not currently working, task is never scheduled
+async def task():
+ # print('task run') uncomment this line when it works
+ pass
+
+
+async def main():
+ print("main start")
+ asyncio.create_task(task())
+ raise ValueError(3)
+ print("main done")
+
+
+try:
+ asyncio.run(main())
+except ValueError as er:
+ print("ValueError", er.args[0])
diff --git a/tests/extmod/uasyncio_exception.py.exp b/tests/extmod/uasyncio_exception.py.exp
new file mode 100644
index 0000000000..b2ee860170
--- /dev/null
+++ b/tests/extmod/uasyncio_exception.py.exp
@@ -0,0 +1,7 @@
+main start
+ValueError 1
+main start
+task start
+ValueError 2
+main start
+ValueError 3
diff --git a/tests/extmod/uasyncio_fair.py b/tests/extmod/uasyncio_fair.py
new file mode 100644
index 0000000000..9b04454bc1
--- /dev/null
+++ b/tests/extmod/uasyncio_fair.py
@@ -0,0 +1,32 @@
+# Test fairness of scheduler
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def task(id, t):
+ print("task start", id)
+ while True:
+ if t > 0:
+ print("task work", id)
+ await asyncio.sleep(t)
+
+
+async def main():
+ t1 = asyncio.create_task(task(1, -0.01))
+ t2 = asyncio.create_task(task(2, 0.1))
+ t3 = asyncio.create_task(task(3, 0.2))
+ await asyncio.sleep(0.5)
+ t1.cancel()
+ t2.cancel()
+ t3.cancel()
+ print("finish")
+
+
+asyncio.run(main())
diff --git a/tests/extmod/uasyncio_fair.py.exp b/tests/extmod/uasyncio_fair.py.exp
new file mode 100644
index 0000000000..4428943f46
--- /dev/null
+++ b/tests/extmod/uasyncio_fair.py.exp
@@ -0,0 +1,12 @@
+task start 1
+task start 2
+task work 2
+task start 3
+task work 3
+task work 2
+task work 3
+task work 2
+task work 2
+task work 3
+task work 2
+finish
diff --git a/tests/extmod/uasyncio_gather.py b/tests/extmod/uasyncio_gather.py
new file mode 100644
index 0000000000..2697a6278b
--- /dev/null
+++ b/tests/extmod/uasyncio_gather.py
@@ -0,0 +1,49 @@
+# test uasyncio.gather() function
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def factorial(name, number):
+ f = 1
+ for i in range(2, number + 1):
+ print("Task {}: Compute factorial({})...".format(name, i))
+ await asyncio.sleep(0.01)
+ f *= i
+ print("Task {}: factorial({}) = {}".format(name, number, f))
+ return f
+
+
+async def task(id):
+ print("start", id)
+ await asyncio.sleep(0.2)
+ print("end", id)
+
+
+async def gather_task():
+ print("gather_task")
+ await asyncio.gather(task(1), task(2))
+ print("gather_task2")
+
+
+async def main():
+ # Simple gather with return values
+ print(await asyncio.gather(factorial("A", 2), factorial("B", 3), factorial("C", 4),))
+
+ # Cancel a multi gather
+ # TODO doesn't work, Task should not forward cancellation from gather to sub-task
+ # but rather CancelledError should cancel the gather directly, which will then cancel
+ # all sub-tasks explicitly
+ # t = asyncio.create_task(gather_task())
+ # await asyncio.sleep(0.1)
+ # t.cancel()
+ # await asyncio.sleep(0.01)
+
+
+asyncio.run(main())
diff --git a/tests/extmod/uasyncio_gather.py.exp b/tests/extmod/uasyncio_gather.py.exp
new file mode 100644
index 0000000000..a37578d7eb
--- /dev/null
+++ b/tests/extmod/uasyncio_gather.py.exp
@@ -0,0 +1,10 @@
+Task A: Compute factorial(2)...
+Task B: Compute factorial(2)...
+Task C: Compute factorial(2)...
+Task A: factorial(2) = 2
+Task B: Compute factorial(3)...
+Task C: Compute factorial(3)...
+Task B: factorial(3) = 6
+Task C: Compute factorial(4)...
+Task C: factorial(4) = 24
+[2, 6, 24]
diff --git a/tests/extmod/uasyncio_get_event_loop.py b/tests/extmod/uasyncio_get_event_loop.py
new file mode 100644
index 0000000000..8ccbd6814e
--- /dev/null
+++ b/tests/extmod/uasyncio_get_event_loop.py
@@ -0,0 +1,20 @@
+# Test get_event_loop()
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def main():
+ print("start")
+ await asyncio.sleep(0.01)
+ print("end")
+
+
+loop = asyncio.get_event_loop()
+loop.run_until_complete(main())
diff --git a/tests/extmod/uasyncio_heaplock.py b/tests/extmod/uasyncio_heaplock.py
new file mode 100644
index 0000000000..771d3f0d97
--- /dev/null
+++ b/tests/extmod/uasyncio_heaplock.py
@@ -0,0 +1,46 @@
+# test that basic scheduling of tasks, and uasyncio.sleep_ms, does not use the heap
+
+import micropython
+
+# strict stackless builds can't call functions without allocating a frame on the heap
+try:
+ f = lambda: 0
+ micropython.heap_lock()
+ f()
+ micropython.heap_unlock()
+except RuntimeError:
+ print("SKIP")
+ raise SystemExit
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def task(id, n, t):
+ for i in range(n):
+ print(id, i)
+ await asyncio.sleep_ms(t)
+
+
+async def main():
+ t1 = asyncio.create_task(task(1, 4, 10))
+ t2 = asyncio.create_task(task(2, 4, 25))
+
+ micropython.heap_lock()
+
+ print("start")
+ await asyncio.sleep_ms(1)
+ print("sleep")
+ await asyncio.sleep_ms(100)
+ print("finish")
+
+ micropython.heap_unlock()
+
+
+asyncio.run(main())
diff --git a/tests/extmod/uasyncio_heaplock.py.exp b/tests/extmod/uasyncio_heaplock.py.exp
new file mode 100644
index 0000000000..a967cc3197
--- /dev/null
+++ b/tests/extmod/uasyncio_heaplock.py.exp
@@ -0,0 +1,11 @@
+start
+1 0
+2 0
+sleep
+1 1
+1 2
+2 1
+1 3
+2 2
+2 3
+finish
diff --git a/tests/extmod/uasyncio_lock.py b/tests/extmod/uasyncio_lock.py
new file mode 100644
index 0000000000..096a8c82be
--- /dev/null
+++ b/tests/extmod/uasyncio_lock.py
@@ -0,0 +1,97 @@
+# Test Lock class
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def task_loop(id, lock):
+ print("task start", id)
+ for i in range(3):
+ async with lock:
+ print("task have", id, i)
+ print("task end", id)
+
+
+async def task_sleep(lock):
+ async with lock:
+ print("task have", lock.locked())
+ await asyncio.sleep(0.2)
+ print("task release", lock.locked())
+ await lock.acquire()
+ print("task have again")
+ lock.release()
+
+
+async def task_cancel(id, lock, to_cancel=None):
+ try:
+ async with lock:
+ print("task got", id)
+ await asyncio.sleep(0.1)
+ print("task release", id)
+ if to_cancel:
+ to_cancel[0].cancel()
+ except asyncio.CancelledError:
+ print("task cancel", id)
+
+
+async def main():
+ lock = asyncio.Lock()
+
+ # Basic acquire/release
+ print(lock.locked())
+ await lock.acquire()
+ print(lock.locked())
+ await asyncio.sleep(0)
+ lock.release()
+ print(lock.locked())
+ await asyncio.sleep(0)
+
+ # Use with "async with"
+ async with lock:
+ print("have lock")
+
+ # 3 tasks wanting the lock
+ print("----")
+ asyncio.create_task(task_loop(1, lock))
+ asyncio.create_task(task_loop(2, lock))
+ t3 = asyncio.create_task(task_loop(3, lock))
+ await lock.acquire()
+ await asyncio.sleep(0)
+ lock.release()
+ await t3
+
+ # 2 sleeping tasks both wanting the lock
+ print("----")
+ asyncio.create_task(task_sleep(lock))
+ await asyncio.sleep(0.1)
+ await task_sleep(lock)
+
+ # 3 tasks, the first cancelling the second, the third should still run
+ print("----")
+ ts = [None]
+ asyncio.create_task(task_cancel(0, lock, ts))
+ ts[0] = asyncio.create_task(task_cancel(1, lock))
+ asyncio.create_task(task_cancel(2, lock))
+ await asyncio.sleep(0.3)
+ print(lock.locked())
+
+ # 3 tasks, the second and third being cancelled while waiting on the lock
+ print("----")
+ t0 = asyncio.create_task(task_cancel(0, lock))
+ t1 = asyncio.create_task(task_cancel(1, lock))
+ t2 = asyncio.create_task(task_cancel(2, lock))
+ await asyncio.sleep(0.05)
+ t1.cancel()
+ await asyncio.sleep(0.1)
+ t2.cancel()
+ await asyncio.sleep(0.1)
+ print(lock.locked())
+
+
+asyncio.run(main())
diff --git a/tests/extmod/uasyncio_lock.py.exp b/tests/extmod/uasyncio_lock.py.exp
new file mode 100644
index 0000000000..a37dfcbd2e
--- /dev/null
+++ b/tests/extmod/uasyncio_lock.py.exp
@@ -0,0 +1,41 @@
+False
+True
+False
+have lock
+----
+task start 1
+task start 2
+task start 3
+task have 1 0
+task have 2 0
+task have 3 0
+task have 1 1
+task have 2 1
+task have 3 1
+task have 1 2
+task end 1
+task have 2 2
+task end 2
+task have 3 2
+task end 3
+----
+task have True
+task release False
+task have True
+task release False
+task have again
+task have again
+----
+task got 0
+task release 0
+task cancel 1
+task got 2
+task release 2
+False
+----
+task got 0
+task cancel 1
+task release 0
+task got 2
+task cancel 2
+False
diff --git a/tests/extmod/uasyncio_lock_cancel.py b/tests/extmod/uasyncio_lock_cancel.py
new file mode 100644
index 0000000000..85b8df8483
--- /dev/null
+++ b/tests/extmod/uasyncio_lock_cancel.py
@@ -0,0 +1,55 @@
+# Test that locks work when cancelling multiple waiters on the lock
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def task(i, lock, lock_flag):
+ print("task", i, "start")
+ try:
+ await lock.acquire()
+ except asyncio.CancelledError:
+ print("task", i, "cancel")
+ return
+ print("task", i, "lock_flag", lock_flag[0])
+ lock_flag[0] = True
+ await asyncio.sleep(0)
+ lock.release()
+ lock_flag[0] = False
+ print("task", i, "done")
+
+
+async def main():
+ # Create a lock and acquire it so the tasks below must wait
+ lock = asyncio.Lock()
+ await lock.acquire()
+ lock_flag = [True]
+
+ # Create 4 tasks and let them all run
+ t0 = asyncio.create_task(task(0, lock, lock_flag))
+ t1 = asyncio.create_task(task(1, lock, lock_flag))
+ t2 = asyncio.create_task(task(2, lock, lock_flag))
+ t3 = asyncio.create_task(task(3, lock, lock_flag))
+ await asyncio.sleep(0)
+
+ # Cancel 2 of the tasks (which are waiting on the lock) and release the lock
+ t1.cancel()
+ t2.cancel()
+ lock.release()
+ lock_flag[0] = False
+
+ # Let the tasks run to completion
+ for _ in range(4):
+ await asyncio.sleep(0)
+
+ # The locke should be unlocked
+ print(lock.locked())
+
+
+asyncio.run(main())
diff --git a/tests/extmod/uasyncio_lock_cancel.py.exp b/tests/extmod/uasyncio_lock_cancel.py.exp
new file mode 100644
index 0000000000..49ae253887
--- /dev/null
+++ b/tests/extmod/uasyncio_lock_cancel.py.exp
@@ -0,0 +1,11 @@
+task 0 start
+task 1 start
+task 2 start
+task 3 start
+task 1 cancel
+task 2 cancel
+task 0 lock_flag False
+task 0 done
+task 3 lock_flag False
+task 3 done
+False
diff --git a/tests/extmod/uasyncio_wait_for.py b/tests/extmod/uasyncio_wait_for.py
new file mode 100644
index 0000000000..92fd174b84
--- /dev/null
+++ b/tests/extmod/uasyncio_wait_for.py
@@ -0,0 +1,62 @@
+# Test asyncio.wait_for
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+async def task(id, t):
+ print("task start", id)
+ await asyncio.sleep(t)
+ print("task end", id)
+ return id * 2
+
+
+async def task_catch():
+ print("task_catch start")
+ try:
+ await asyncio.sleep(0.2)
+ except asyncio.CancelledError:
+ print("ignore cancel")
+ print("task_catch done")
+
+
+async def task_raise():
+ print("task start")
+ raise ValueError
+
+
+async def main():
+ # When task finished before the timeout
+ print(await asyncio.wait_for(task(1, 0.01), 10))
+
+ # When timeout passes and task is cancelled
+ try:
+ print(await asyncio.wait_for(task(2, 10), 0.01))
+ except asyncio.TimeoutError:
+ print("timeout")
+
+ # When timeout passes and task is cancelled, but task ignores the cancellation request
+ try:
+ print(await asyncio.wait_for(task_catch(), 0.1))
+ except asyncio.TimeoutError:
+ print("TimeoutError")
+
+ # When task raises an exception
+ try:
+ print(await asyncio.wait_for(task_raise(), 1))
+ except ValueError:
+ print("ValueError")
+
+ # Timeout of None means wait forever
+ print(await asyncio.wait_for(task(3, 0.1), None))
+
+ print("finish")
+
+
+asyncio.run(main())
diff --git a/tests/extmod/uasyncio_wait_for.py.exp b/tests/extmod/uasyncio_wait_for.py.exp
new file mode 100644
index 0000000000..41a5f2481e
--- /dev/null
+++ b/tests/extmod/uasyncio_wait_for.py.exp
@@ -0,0 +1,15 @@
+task start 1
+task end 1
+2
+task start 2
+timeout
+task_catch start
+ignore cancel
+task_catch done
+TimeoutError
+task start
+ValueError
+task start 3
+task end 3
+6
+finish
diff --git a/tests/extmod/uasyncio_wait_task.py b/tests/extmod/uasyncio_wait_task.py
new file mode 100644
index 0000000000..3c79320c9f
--- /dev/null
+++ b/tests/extmod/uasyncio_wait_task.py
@@ -0,0 +1,77 @@
+# Test waiting on a task
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+try:
+ import utime
+
+ ticks = utime.ticks_ms
+ ticks_diff = utime.ticks_diff
+except:
+ import time
+
+ ticks = lambda: int(time.time() * 1000)
+ ticks_diff = lambda t1, t0: t1 - t0
+
+
+async def task(t):
+ print("task", t)
+
+
+async def delay_print(t, s):
+ await asyncio.sleep(t)
+ print(s)
+
+
+async def task_raise():
+ print("task_raise")
+ raise ValueError
+
+
+async def main():
+ print("start")
+
+ # Wait on a task
+ t = asyncio.create_task(task(1))
+ await t
+
+ # Wait on a task that's already done
+ t = asyncio.create_task(task(2))
+ await asyncio.sleep(0.001)
+ await t
+
+ # Wait again on same task
+ await t
+
+ print("----")
+
+ # Create 2 tasks
+ ts1 = asyncio.create_task(delay_print(0.04, "hello"))
+ ts2 = asyncio.create_task(delay_print(0.08, "world"))
+
+ # Time how long the tasks take to finish, they should execute in parallel
+ print("start")
+ t0 = ticks()
+ await ts1
+ t1 = ticks()
+ await ts2
+ t2 = ticks()
+ print("took {} {}".format(round(ticks_diff(t1, t0), -1), round(ticks_diff(t2, t1), -1)))
+
+ # Wait on a task that raises an exception
+ t = asyncio.create_task(task_raise())
+ try:
+ await t
+ except ValueError:
+ print("ValueError")
+
+
+asyncio.run(main())
diff --git a/tests/extmod/uasyncio_wait_task.py.exp b/tests/extmod/uasyncio_wait_task.py.exp
new file mode 100644
index 0000000000..ee4e70fb4e
--- /dev/null
+++ b/tests/extmod/uasyncio_wait_task.py.exp
@@ -0,0 +1,10 @@
+start
+task 1
+task 2
+----
+start
+hello
+world
+took 40 40
+task_raise
+ValueError