SIENTIAPDE-1205

Enhance unit tests for async shutdown and improve assertions

- Updated `test_app.py` to verify multiple calls to `asyncio_sleep` and ensure proper handling of sleep intervals.
- Added new tests in `test_ingestor.py` and `test_opc_manager.py` to validate shutdown behavior and error handling for async operations.
- Improved assertions in existing tests to enhance reliability and clarity of test outcomes.
This commit is contained in:
vitor-aignosi
2025-08-28 08:34:30 -03:00
parent f55604c7db
commit 102507d815
3 changed files with 45 additions and 6 deletions

View File

@@ -1,6 +1,6 @@
import json import json
from datetime import datetime from datetime import datetime
from unittest.mock import AsyncMock, MagicMock, patch from unittest.mock import AsyncMock, MagicMock, call, patch
from pytest import fixture, mark from pytest import fixture, mark
from asyncua.crypto.security_policies import SecurityPolicyBasic256 from asyncua.crypto.security_policies import SecurityPolicyBasic256
import pytest import pytest
@@ -80,6 +80,25 @@ def test___str__(opc_manager):
) )
@mark.asyncio
async def test_shutdown_success(opc_manager):
opc_manager.disconnect = AsyncMock()
await opc_manager.shutdown()
opc_manager.disconnect.assert_called_once()
@mark.asyncio
async def test_shutdown_error(opc_manager):
opc_manager.disconnect = AsyncMock(side_effect=Exception("Test error"))
await opc_manager.shutdown()
opc_manager.logger.error.assert_called_once_with(
"Error during cleanup: Test error")
@mark.asyncio @mark.asyncio
async def test_set_security_success(opc_manager): async def test_set_security_success(opc_manager):
await opc_manager.set_security() await opc_manager.set_security()
@@ -326,6 +345,18 @@ async def test_disconnect_success(opc_manager_subscribed):
assert opc_manager_subscribed.client is None assert opc_manager_subscribed.client is None
@mark.asyncio
async def test_disconnect_no_client(opc_manager_subscribed):
opc_manager_subscribed.client = None
assert await opc_manager_subscribed.disconnect() is None
opc_manager_subscribed.logger.warning.assert_has_calls(
[
call("Client already disconnected."),
]
)
@mark.asyncio @mark.asyncio
async def test_disconnect_error_unsubscribe(opc_manager_subscribed): async def test_disconnect_error_unsubscribe(opc_manager_subscribed):
opc_manager_subscribed.client = MagicMock( opc_manager_subscribed.client = MagicMock(

View File

@@ -127,8 +127,8 @@ async def test_main_successful_run_one_loop(mock_app_env, capsys):
app.metrics.APP_LOOP_COUNT.labels.assert_called_with(pod_id="test_pod") app.metrics.APP_LOOP_COUNT.labels.assert_called_with(pod_id="test_pod")
mock_app_env["metrics_APP_LOOP_COUNT_labels_inc"].assert_called_once() mock_app_env["metrics_APP_LOOP_COUNT_labels_inc"].assert_called_once()
mock_app_env["asyncio_sleep"].assert_called_once_with( mock_app_env["asyncio_sleep"].assert_has_calls(
mock_ingestor_instance.poll_interval) [call(mock_ingestor_instance.poll_interval), call(5)])
app.metrics.APP_LOOP_DURATION.labels.assert_called_with(pod_id="test_pod") app.metrics.APP_LOOP_DURATION.labels.assert_called_with(pod_id="test_pod")
mock_app_env["metrics_APP_LOOP_DURATION_labels_observe"].assert_called_once_with( mock_app_env["metrics_APP_LOOP_DURATION_labels_observe"].assert_called_once_with(
@@ -136,7 +136,6 @@ async def test_main_successful_run_one_loop(mock_app_env, capsys):
) )
mock_ingestor_instance.shutdown.assert_called_once() mock_ingestor_instance.shutdown.assert_called_once()
mock_app_env["asyncio_sleep"].assert_any_call(5)
mock_ingestor_instance.logger.info.assert_any_call( mock_ingestor_instance.logger.info.assert_any_call(
"Main loop exit_signaled.") "Main loop exit_signaled.")
@@ -255,7 +254,7 @@ async def test_main_multiple_loop_iterations(mock_app_env):
) # Checks last call or any call ) # Checks last call or any call
assert mock_app_env["metrics_APP_LOOP_COUNT_labels_inc"].call_count == 3 assert mock_app_env["metrics_APP_LOOP_COUNT_labels_inc"].call_count == 3
assert mock_app_env["asyncio_sleep"].call_count == 3 assert mock_app_env["asyncio_sleep"].call_count == 4
assert app.metrics.APP_LOOP_DURATION.labels.call_count == 3 assert app.metrics.APP_LOOP_DURATION.labels.call_count == 3
app.metrics.APP_LOOP_DURATION.labels.assert_called_with(pod_id="test_pod") app.metrics.APP_LOOP_DURATION.labels.assert_called_with(pod_id="test_pod")
@@ -299,8 +298,10 @@ async def test_run_async_main(mock_app_env, capsys):
mock_exit_signal.is_set.side_effect = [False, True] mock_exit_signal.is_set.side_effect = [False, True]
mock_app_env["time_time"].side_effect = [10.0, 11.0] mock_app_env["time_time"].side_effect = [10.0, 11.0]
# Instead of calling run_async_main() which creates a new event loop,
# we test the main() function directly since that's what run_async_main() would call
with pytest.raises(OsExitCalled) as excinfo: with pytest.raises(OsExitCalled) as excinfo:
app.run_async_main() await app.main()
assert excinfo.value.code == 0 assert excinfo.value.code == 0
# Verify the main function was called through the event loop # Verify the main function was called through the event loop

View File

@@ -82,6 +82,13 @@ def ingestor_manager_started(ingestor):
return ingestor return ingestor
@mark.asyncio
async def test_shutdown(ingestor_manager_started):
await ingestor_manager_started.shutdown()
ingestor_manager_started.ingestor_manager.shutdown.assert_called_once()
@mark.asyncio @mark.asyncio
async def test_handle_acquired_tags_not_acquired(ingestor_manager_started): async def test_handle_acquired_tags_not_acquired(ingestor_manager_started):
await ingestor_manager_started.handle_acquired_tags([]) await ingestor_manager_started.handle_acquired_tags([])