Beispiel #1
0
    def test_schedule_later(self):
        control_ticks = 0
        deferred_ticks = 0
        deferred_ticked = False
        loop = Loop(debug=False)

        async def deferred_task():
            nonlocal deferred_ticked, deferred_ticks
            deferred_ticks = deferred_ticks + 1
            deferred_ticked = True

        async def control_ticker():
            nonlocal control_ticks
            control_ticks = control_ticks + 1

        loop.schedule(100, control_ticker)
        loop.schedule_later(10, deferred_task)

        while True:
            loop._step()
            if deferred_ticked:
                break

        self.assertEqual(deferred_ticks, 1)
        self.assertAlmostEqual(control_ticks, 10, delta=2)
Beispiel #2
0
    def test_add_task(self):
        loop = Loop()
        ran = False

        async def foo():
            nonlocal ran
            ran = True

        loop.add_task(foo())
        loop._step()
        self.assertTrue(ran)
Beispiel #3
0
    def test_delay(self):
        loop = Loop()
        complete = False

        async def foo():
            nonlocal complete
            await loop.delay(0.1)
            complete = True

        loop.add_task(foo())
        start = time.monotonic()
        while not complete and time.monotonic() - start < 1:
            loop._step()
        self.assertTrue(complete)
Beispiel #4
0
    def test_run_later(self):
        loop = Loop()
        count = 0

        async def run_later():
            nonlocal count
            while True:
                count = count + 1
                await _yield_once()  # For testing

        loop.run_later(seconds_to_delay=0.1, awaitable_task=run_later())

        self.assertEqual(
            0, count,
            'count should not increment upon coroutine instantiation')
        loop._step()
        self.assertEqual(
            0, count, 'count should not increment before waiting long enough')

        time.sleep(
            0.1
        )  # Make sure enough time has passed for step to pick up the task
        loop._step()
        self.assertEqual(1, count, 'count should increment once per step')
Beispiel #5
0
    def test_schedule_rate(self):
        # Checks a bunch of scheduled tasks to make sure they hit their target fixed rate schedule.
        # Pathological scheduling sees these tasks barge in front of others all the time. Many run
        # at a fairly high frequency.

        loop = Loop(debug=False)
        duration = 1  # Seconds to run the scheduler. (try with 10s if you suspect scheduler drift)
        tasks = 110  # How many tasks (higher indexes count faster. 110th index goes 100hz)

        def timer(index):
            return Duration.of_milliseconds(120 - index)

        counters = []
        for i in range(tasks):

            async def f(_i):
                counters[_i] += 1

            counters.append(0)

            loop.schedule(timer(i), f, i)

        start = time.perf_counter()
        end = start
        while end - start < duration:
            loop._step()
            end = time.perf_counter()
        print()

        expected_tps = 0
        actual_tps = 0
        # Assert that all the tasks hit their scheduled count, at least within +-5 iterations.
        for i in range(len(counters)):
            self.assertAlmostEqual(duration * timer(i).as_frequency(),
                                   counters[i],
                                   delta=2)
            expected_tps += timer(i).as_frequency()
            actual_tps += counters[i]
        actual_tps /= duration
        print('expected tps:', expected_tps, 'actual:', actual_tps)
    def test_acquire(self):
        loop = Loop()

        # Synchronize access to an SPI allowing other tasks to work while waiting
        spi_bus = 'board.SPI'
        managed_spi = ManagedSpi(spi_bus, loop=loop)

        # Configure 3 pins for selecting different chip selects on the shared SPI bus
        sdcard_spi = managed_spi.cs_handle(FakeDigitalIO('D1'))
        screen_spi = managed_spi.cs_handle(FakeDigitalIO('D2'))
        sensor_spi = managed_spi.cs_handle(FakeDigitalIO('D3'))

        did_read = did_screen = did_sensor = False

        # Define 3 full while True app loops dependent on 1 shared SPI
        async def read_sdcard():
            nonlocal did_read
            while True:
                async with sdcard_spi as spi:
                    # do_something_with(spi)
                    for _ in range(2):
                        self.assertTrue(sdcard_spi.active)
                        self.assertFalse(screen_spi.active)
                        self.assertFalse(sensor_spi.active)
                        await YieldOne()
                did_read = True
                await YieldOne()

        async def update_screen():
            nonlocal did_screen
            while True:
                # await do_other_work
                async with screen_spi as spi:
                    for _ in range(2):
                        self.assertFalse(sdcard_spi.active)
                        self.assertTrue(screen_spi.active)
                        self.assertFalse(sensor_spi.active)
                        await YieldOne()
                did_screen = True
                await YieldOne()

        async def read_sensor():
            nonlocal did_sensor
            while True:
                async with sensor_spi as spi:
                    for _ in range(2):
                        self.assertFalse(sdcard_spi.active)
                        self.assertFalse(screen_spi.active)
                        self.assertTrue(sensor_spi.active)
                        await YieldOne()
                did_sensor = True
                await YieldOne()

        # Add the top level application coroutines
        loop.add_task(read_sdcard())
        loop.add_task(read_sensor())
        loop.add_task(update_screen())

        # would just use asynccp.add_task() and asynccp.run() but for test let's manually step it through
        # loop.run()

        # They didn't run yet
        self.assertFalse(sdcard_spi.active)
        self.assertFalse(screen_spi.active)
        self.assertFalse(sensor_spi.active)

        loop._step()
        self.assertTrue(sdcard_spi.active)  # sdcard was the first to queue up
        loop._step()
        loop._step()

        loop._step()
        self.assertTrue(sensor_spi.active)  # sensor was the second to queue up
        loop._step()
        loop._step()

        loop._step()
        self.assertTrue(screen_spi.active)  # screen was the last to queue up
        loop._step()
        loop._step()

        self.assertTrue(did_sensor)
        self.assertTrue(did_screen)
        self.assertTrue(did_read)
Beispiel #7
0
    def test_reschedule(self):
        now = 0

        def nanos():
            nonlocal now
            return now

        set_time_provider(nanos)
        try:
            loop = Loop()
            run_count = 0

            async def foo():
                nonlocal run_count
                run_count += 1

            scheduled_task = loop.schedule(1000000000, foo)

            now = 2
            self.assertEqual(0, run_count, 'did not run before step')
            loop._step()
            self.assertEqual(1, run_count, 'ran only once during step')

            now = 4
            scheduled_task.stop()
            loop._step()
            self.assertEqual(1, run_count, 'does not run again while stopped')

            now = 6
            scheduled_task.start()
            loop._step()
            self.assertEqual(2, run_count, 'runs again after restarting')

            now = 7
            scheduled_task.change_rate(1000000000 / 10)
            loop._step()
            self.assertEqual(
                3, run_count,
                'this run was already scheduled. the next one will be at 10-step'
            )

            now = 16
            loop._step()
            self.assertEqual(3, run_count, 'expect to run after 10 has passed')

            now = 17
            loop._step()
            self.assertEqual(4, run_count, 'new schedule rate ran')
        finally:
            set_time_provider(time.monotonic_ns)