diff --git a/app/src/async_stream.py b/app/src/async_stream.py index 3676f96..21bb6b9 100644 --- a/app/src/async_stream.py +++ b/app/src/async_stream.py @@ -179,10 +179,11 @@ class AsyncStream(AsyncIfcImpl): self.proc_start = time.time() while True: try: - proc = time.time() - self.proc_start - if proc > self.proc_max: - self.proc_max = proc - self.proc_start = None + if self.proc_start: + proc = time.time() - self.proc_start + if proc > self.proc_max: + self.proc_max = proc + self.proc_start = None dead_conn_to = self.__timeout() await asyncio.wait_for(self.__async_read(), dead_conn_to) diff --git a/app/tests/test_async_stream.py b/app/tests/test_async_stream.py index 864f2c3..afe0039 100644 --- a/app/tests/test_async_stream.py +++ b/app/tests/test_async_stream.py @@ -2,6 +2,7 @@ import pytest import asyncio import gc +import time from app.src.infos import Infos from app.src.inverter_base import InverterBase @@ -38,6 +39,26 @@ def test_timeout_cb(): cnt += 1 assert cnt == 0 +def test_health(): + reader = FakeReader() + writer = FakeWriter() + + ifc = AsyncStreamClient(reader, writer, None, None) + ifc.proc_start = time.time() + assert ifc.healthy() + ifc.proc_start = time.time() -10 + assert not ifc.healthy() + ifc.proc_start = None + assert ifc.healthy() + + del ifc + + cnt = 0 + for inv in InverterBase: + print(f'InverterBase refs:{gc.get_referrers(inv)}') + cnt += 1 + assert cnt == 0 + @pytest.mark.asyncio async def test_close_cb(): assert asyncio.get_running_loop() @@ -92,6 +113,8 @@ async def test_read(): ifc.close() # clears the closed callback cnt += 1 def app_read(): + nonlocal ifc + ifc.proc_start -= 3 return 0.01 # async wait of 0.01 cnt = 0 ifc = AsyncStreamClient(reader, writer, None, closed) @@ -99,6 +122,7 @@ async def test_read(): ifc.rx_set_cb(app_read) await ifc.client_loop('') print('End loop') + assert ifc.proc_max >= 3 assert 13 == ifc.rx_len() assert cnt == 1 del ifc @@ -205,3 +229,64 @@ async def test_create_remote_cb(): print(f'InverterBase refs:{gc.get_referrers(inv)}') cnt += 1 assert cnt == 0 + +@pytest.mark.asyncio +async def test_sw_exception(): + global test + assert asyncio.get_running_loop() + reader = FakeReader() + reader.test = FakeReader.RD_TEST_SW_EXCEPT + reader.on_recv.set() + writer = FakeWriter() + cnt = 0 + def timeout(): + return 1 + def closed(): + nonlocal cnt + nonlocal ifc + ifc.close() # clears the closed callback + cnt += 1 + cnt = 0 + ifc = AsyncStreamClient(reader, writer, None, closed) + ifc.prot_set_timeout_cb(timeout) + await ifc.client_loop('') + print('End loop') + assert cnt == 1 + del ifc + + cnt = 0 + for inv in InverterBase: + print(f'InverterBase refs:{gc.get_referrers(inv)}') + cnt += 1 + assert cnt == 0 + +@pytest.mark.asyncio +async def test_os_error(): + global test + assert asyncio.get_running_loop() + reader = FakeReader() + reader.test = FakeReader.RD_TEST_OS_ERROR + + reader.on_recv.set() + writer = FakeWriter() + cnt = 0 + def timeout(): + return 1 + def closed(): + nonlocal cnt + nonlocal ifc + ifc.close() # clears the closed callback + cnt += 1 + cnt = 0 + ifc = AsyncStreamClient(reader, writer, None, closed) + ifc.prot_set_timeout_cb(timeout) + await ifc.client_loop('') + print('End loop') + assert cnt == 1 + del ifc + + cnt = 0 + for inv in InverterBase: + print(f'InverterBase refs:{gc.get_referrers(inv)}') + cnt += 1 + assert cnt == 0 diff --git a/app/tests/test_modbus_tcp.py b/app/tests/test_modbus_tcp.py index 6a33727..a39c2cd 100644 --- a/app/tests/test_modbus_tcp.py +++ b/app/tests/test_modbus_tcp.py @@ -75,6 +75,8 @@ class FakeReader(): RD_TEST_0_BYTES = 1 RD_TEST_TIMEOUT = 2 RD_TEST_13_BYTES = 3 + RD_TEST_SW_EXCEPT = 4 + RD_TEST_OS_ERROR = 5 def __init__(self): self.on_recv = asyncio.Event() @@ -91,6 +93,13 @@ class FakeReader(): return b'test-data-req' elif self.test == self.RD_TEST_TIMEOUT: raise TimeoutError + elif self.test == self.RD_TEST_SW_EXCEPT: + self.test = self.RD_TEST_0_BYTES + self.unknown_var += 1 + elif self.test == self.RD_TEST_OS_ERROR: + self.test = self.RD_TEST_0_BYTES + raise ConnectionRefusedError + def feed_eof(self): return