SIENTIAPDE-1163
SIENTIAPDE-1163 Enhance OPC tests to improve error handling and notifications. Added tests for MongoDB configuration and refined connection error handling in OPC repository.
This commit is contained in:
@@ -16,11 +16,28 @@ metadata = {
|
|||||||
|
|
||||||
|
|
||||||
@patch("laborious.activities.opc.OpcRepository")
|
@patch("laborious.activities.opc.OpcRepository")
|
||||||
def test___init__(mock_opc_repository):
|
@patch("laborious.activities.opc.OPC.send_notification")
|
||||||
|
def test___init__(mock_send_notification, mock_opc_repository):
|
||||||
mock_logger = MagicMock()
|
mock_logger = MagicMock()
|
||||||
server1 = MagicMock()
|
server1 = MagicMock(
|
||||||
server2 = MagicMock()
|
connect=MagicMock(return_value=(True, {})),
|
||||||
mock_opc_repository.side_effect = [server1, server2]
|
write_data=MagicMock(return_value=(True, {}))
|
||||||
|
)
|
||||||
|
server2 = MagicMock(
|
||||||
|
connect=MagicMock(return_value=(True, {})),
|
||||||
|
write_data=MagicMock(return_value=(True, {}))
|
||||||
|
)
|
||||||
|
server3 = MagicMock(
|
||||||
|
connect=MagicMock(return_value=(False, {
|
||||||
|
'notification_id': 'OPC_CONNECTION_ERROR_server3',
|
||||||
|
'message': 'Failed to connect to OPC server: Test error',
|
||||||
|
'block': 'opc_repository',
|
||||||
|
'level': NotificationLevel.ERROR,
|
||||||
|
'attachment_content': 'Test error'
|
||||||
|
})),
|
||||||
|
write_data=MagicMock(return_value=(True, {}))
|
||||||
|
)
|
||||||
|
mock_opc_repository.side_effect = [server1, server2, server3]
|
||||||
mock_notification_handler = MagicMock()
|
mock_notification_handler = MagicMock()
|
||||||
servers = {
|
servers = {
|
||||||
'server1': {
|
'server1': {
|
||||||
@@ -40,6 +57,15 @@ def test___init__(mock_opc_repository):
|
|||||||
'private_key_path': '',
|
'private_key_path': '',
|
||||||
'server_cert_path': '',
|
'server_cert_path': '',
|
||||||
'reconnection_interval': 60,
|
'reconnection_interval': 60,
|
||||||
|
},
|
||||||
|
'server3': {
|
||||||
|
'id': 'server3',
|
||||||
|
'url': 'http://localhost:8080',
|
||||||
|
'server_uri': 'opc.tcp://localhost:4840',
|
||||||
|
'cert_path': '',
|
||||||
|
'private_key_path': '',
|
||||||
|
'server_cert_path': '',
|
||||||
|
'reconnection_interval': 60,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
opc = OPC(
|
opc = OPC(
|
||||||
@@ -84,6 +110,22 @@ def test___init__(mock_opc_repository):
|
|||||||
server1.connect.assert_called_once()
|
server1.connect.assert_called_once()
|
||||||
server2.connect.assert_called_once()
|
server2.connect.assert_called_once()
|
||||||
|
|
||||||
|
mock_send_notification.assert_has_calls([
|
||||||
|
call(
|
||||||
|
metadata={
|
||||||
|
'model_id': '-',
|
||||||
|
'model_name': '-',
|
||||||
|
'workflow_name': '-',
|
||||||
|
'schedule_name': 'INITIALIZATION'
|
||||||
|
},
|
||||||
|
notification_id="OPC_CONNECTION_ERROR_server3",
|
||||||
|
message="Failed to connect to OPC server: Test error",
|
||||||
|
block="opc_repository",
|
||||||
|
level=NotificationLevel.ERROR,
|
||||||
|
attachment_content=ANY
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
@patch("laborious.activities.opc.OpcRepository")
|
@patch("laborious.activities.opc.OpcRepository")
|
||||||
@@ -99,8 +141,12 @@ def opc(mock_opc_repository):
|
|||||||
'reconnection_interval': 60,
|
'reconnection_interval': 60,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mock_opc_repository.write_data = MagicMock(
|
|
||||||
return_value=True
|
mock_opc_repository.return_value.write_data = MagicMock(
|
||||||
|
return_value=(True, {})
|
||||||
|
)
|
||||||
|
mock_opc_repository.return_value.connect = MagicMock(
|
||||||
|
return_value=(True, {})
|
||||||
)
|
)
|
||||||
opc = OPC(
|
opc = OPC(
|
||||||
opc_servers=servers,
|
opc_servers=servers,
|
||||||
@@ -128,6 +174,28 @@ def test_write_data_success(opc, tag, data_type, data):
|
|||||||
tag, data, data_type, opc.logger, metadata)
|
tag, data, data_type, opc.logger, metadata)
|
||||||
|
|
||||||
|
|
||||||
|
def test_write_data_failed(opc):
|
||||||
|
opc.opc_repository['server1'].write_data.return_value = (False, {
|
||||||
|
'notification_id': 'OPC_WRITE_DATA_ERROR_server1',
|
||||||
|
'message': 'Failed to write data to OPC server: Test error',
|
||||||
|
'block': 'opc_repository',
|
||||||
|
'level': NotificationLevel.ERROR,
|
||||||
|
'attachment_content': 'Test error'
|
||||||
|
})
|
||||||
|
|
||||||
|
assert opc.write_data(server_id='server1', tag='tag1', data=50,
|
||||||
|
data_type='int', tag_type='prediction', metadata=metadata) is False
|
||||||
|
|
||||||
|
opc.send_notification.assert_called_once_with(
|
||||||
|
metadata=metadata,
|
||||||
|
notification_id="OPC_WRITE_DATA_ERROR_server1",
|
||||||
|
message="Failed to write data to OPC server: Test error",
|
||||||
|
block="opc_repository",
|
||||||
|
level=NotificationLevel.ERROR,
|
||||||
|
attachment_content=ANY
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_write_data_exception(opc):
|
def test_write_data_exception(opc):
|
||||||
opc.opc_repository['server1'].write_data.side_effect = Exception(
|
opc.opc_repository['server1'].write_data.side_effect = Exception(
|
||||||
"Test error")
|
"Test error")
|
||||||
|
|||||||
@@ -115,17 +115,15 @@ def test_try_connect_fail(opc_repository):
|
|||||||
opc_repository.client = MagicMock()
|
opc_repository.client = MagicMock()
|
||||||
opc_repository.client.connect.side_effect = Exception("Test error")
|
opc_repository.client.connect.side_effect = Exception("Test error")
|
||||||
|
|
||||||
opc_repository.try_connect()
|
is_connected, error_data = opc_repository.try_connect()
|
||||||
|
|
||||||
opc_repository.client.connect.assert_called_once()
|
opc_repository.client.connect.assert_called_once()
|
||||||
assert opc_repository.last_reconnection_time is not None
|
assert is_connected is False
|
||||||
opc_repository.notification_handler.build_and_send_notification.assert_called_once_with(
|
assert error_data['notification_id'] == f"OPC_CONNECTION_ERROR_{opc_repository.id}"
|
||||||
notification_id=f"OPC_CONNECTION_ERROR_{opc_repository.id}",
|
assert error_data['message'] == "Failed to connect to OPC server: Test error"
|
||||||
message="Failed to connect to OPC server: Test error",
|
assert error_data['block'] == "opc_repository"
|
||||||
block="opc_repository",
|
assert error_data['level'] == NotificationLevel.ERROR
|
||||||
level=NotificationLevel.ERROR,
|
assert error_data['attachment_content'] is not None
|
||||||
attachment_content=ANY
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_disconnect(opc_repository, mock_client):
|
def test_disconnect(opc_repository, mock_client):
|
||||||
@@ -184,7 +182,7 @@ def test_validate_connection_lost_not_time_to_reconect(_mock_datetime, opc_repos
|
|||||||
|
|
||||||
response = opc_repository.validate_connection()
|
response = opc_repository.validate_connection()
|
||||||
opc_repository.try_connect.assert_not_called()
|
opc_repository.try_connect.assert_not_called()
|
||||||
assert response is False
|
assert response == (False, {})
|
||||||
|
|
||||||
|
|
||||||
@patch('laborious.utils.repository.opc_repository.hasattr', return_value=True)
|
@patch('laborious.utils.repository.opc_repository.hasattr', return_value=True)
|
||||||
@@ -207,11 +205,11 @@ def test_validate_connection_failed(opc_repository):
|
|||||||
opc_repository.error_count = 0
|
opc_repository.error_count = 0
|
||||||
|
|
||||||
output = opc_repository.validate_connection()
|
output = opc_repository.validate_connection()
|
||||||
assert output is True
|
assert output == (True, {})
|
||||||
|
|
||||||
|
|
||||||
def test_write_data_validate_connection_do_nothing(opc_repository):
|
def test_write_data_validate_connection_do_nothing(opc_repository):
|
||||||
opc_repository.validate_connection = MagicMock(return_value=True)
|
opc_repository.validate_connection = MagicMock(return_value=(True, {}))
|
||||||
opc_repository.client = MagicMock()
|
opc_repository.client = MagicMock()
|
||||||
opc_repository.write_data("ns=2;s=TestNode", 42.0,
|
opc_repository.write_data("ns=2;s=TestNode", 42.0,
|
||||||
"float", opc_repository.logger, metadata)
|
"float", opc_repository.logger, metadata)
|
||||||
@@ -220,7 +218,7 @@ def test_write_data_validate_connection_do_nothing(opc_repository):
|
|||||||
|
|
||||||
|
|
||||||
def test_write_data_validate_connection_failed(opc_repository):
|
def test_write_data_validate_connection_failed(opc_repository):
|
||||||
opc_repository.validate_connection = MagicMock(return_value=False)
|
opc_repository.validate_connection = MagicMock(return_value=(False, {}))
|
||||||
opc_repository.client = MagicMock()
|
opc_repository.client = MagicMock()
|
||||||
opc_repository.error_count = 0
|
opc_repository.error_count = 0
|
||||||
opc_repository.write_data("ns=2;s=TestNode", 42.0,
|
opc_repository.write_data("ns=2;s=TestNode", 42.0,
|
||||||
@@ -230,45 +228,43 @@ def test_write_data_validate_connection_failed(opc_repository):
|
|||||||
|
|
||||||
|
|
||||||
def test_write_data_get_node_failed(opc_repository):
|
def test_write_data_get_node_failed(opc_repository):
|
||||||
opc_repository.validate_connection = MagicMock(return_value=True)
|
opc_repository.validate_connection = MagicMock(return_value=(True, {}))
|
||||||
opc_repository.client = MagicMock()
|
opc_repository.client = MagicMock()
|
||||||
opc_repository.error_count = 0
|
opc_repository.error_count = 0
|
||||||
opc_repository.client.get_node.side_effect = Exception("Test error")
|
opc_repository.client.get_node.side_effect = Exception("Test error")
|
||||||
opc_repository.write_data("ns=2;s=TestNode", 42.0,
|
is_success, error_data = opc_repository.write_data("ns=2;s=TestNode", 42.0,
|
||||||
"float", opc_repository.logger, metadata)
|
"float", opc_repository.logger, metadata)
|
||||||
opc_repository.validate_connection.assert_called_once()
|
opc_repository.validate_connection.assert_called_once()
|
||||||
opc_repository.client.get_node.assert_called_once_with("ns=2;s=TestNode")
|
opc_repository.client.get_node.assert_called_once_with("ns=2;s=TestNode")
|
||||||
opc_repository.notification_handler.build_and_send_notification.assert_called_once_with(
|
assert is_success is False
|
||||||
notification_id=f"OPC_WRITE_GET_NODE_ERROR_{opc_repository.id}",
|
assert error_data['notification_id'] == f"OPC_WRITE_GET_NODE_ERROR_{opc_repository.id}"
|
||||||
message="Failed to get node from OPC server: Test error | metadata: {'metadata': {'model_id': 'test_model', 'model_name': 'test_model', 'workflow_name': 'test_workflow', 'schema_name': 'test_schedule'}}",
|
assert error_data['message'] == "Failed to get node from OPC server: Test error | metadata: {'metadata': {'model_id': 'test_model', 'model_name': 'test_model', 'workflow_name': 'test_workflow', 'schema_name': 'test_schedule'}}"
|
||||||
block="opc_repository",
|
assert error_data['block'] == "opc_repository"
|
||||||
level=NotificationLevel.ERROR,
|
assert error_data['level'] == NotificationLevel.ERROR
|
||||||
attachment_content=ANY
|
assert error_data['attachment_content'] is not None
|
||||||
)
|
|
||||||
assert opc_repository.error_count == 1
|
|
||||||
|
|
||||||
|
|
||||||
def test_write_data_invalid_data_type(opc_repository, mock_client):
|
def test_write_data_invalid_data_type(opc_repository, mock_client):
|
||||||
opc_repository.validate_connection = MagicMock(return_value=True)
|
opc_repository.validate_connection = MagicMock(return_value=(True, {}))
|
||||||
opc_repository.client = mock_client
|
opc_repository.client = mock_client
|
||||||
mock_node = MagicMock()
|
mock_node = MagicMock()
|
||||||
mock_client.get_node.return_value = mock_node
|
mock_client.get_node.return_value = mock_node
|
||||||
|
|
||||||
opc_repository.write_data("ns=2;s=TestNode", 42.0,
|
is_success, error_data = opc_repository.write_data("ns=2;s=TestNode", 42.0,
|
||||||
"invalid_type", opc_repository.logger, metadata)
|
"invalid_type", opc_repository.logger, metadata)
|
||||||
opc_repository.validate_connection.assert_called_once()
|
opc_repository.validate_connection.assert_called_once()
|
||||||
mock_client.get_node.assert_called_once_with("ns=2;s=TestNode")
|
mock_client.get_node.assert_called_once_with("ns=2;s=TestNode")
|
||||||
|
|
||||||
opc_repository.notification_handler.build_and_send_notification.assert_called_once_with(
|
assert is_success is False
|
||||||
notification_id=f"OPC_WRITE_DATA_TYPE_ERROR_{opc_repository.id}",
|
assert error_data['notification_id'] == f"OPC_WRITE_DATA_TYPE_ERROR_{opc_repository.id}"
|
||||||
message="Unsupported data type: invalid_type | metadata: {'metadata': {'model_id': 'test_model', 'model_name': 'test_model', 'workflow_name': 'test_workflow', 'schema_name': 'test_schedule'}}",
|
assert error_data['message'] == "Unsupported data type: invalid_type | metadata: {'metadata': {'model_id': 'test_model', 'model_name': 'test_model', 'workflow_name': 'test_workflow', 'schema_name': 'test_schedule'}}"
|
||||||
block="opc_repository",
|
assert error_data['block'] == "opc_repository"
|
||||||
level=NotificationLevel.ERROR
|
assert error_data['level'] == NotificationLevel.ERROR
|
||||||
)
|
assert error_data.get('attachment_content') is None
|
||||||
|
|
||||||
|
|
||||||
def test_write_data(opc_repository, mock_client):
|
def test_write_data(opc_repository, mock_client):
|
||||||
opc_repository.validate_connection = MagicMock(return_value=True)
|
opc_repository.validate_connection = MagicMock(return_value=(True, {}))
|
||||||
opc_repository.client = mock_client
|
opc_repository.client = mock_client
|
||||||
mock_node = MagicMock()
|
mock_node = MagicMock()
|
||||||
mock_client.get_node.return_value = mock_node
|
mock_client.get_node.return_value = mock_node
|
||||||
@@ -281,22 +277,20 @@ def test_write_data(opc_repository, mock_client):
|
|||||||
|
|
||||||
|
|
||||||
def test_write_data_write_value_failed(opc_repository, mock_client):
|
def test_write_data_write_value_failed(opc_repository, mock_client):
|
||||||
opc_repository.validate_connection = MagicMock(return_value=True)
|
opc_repository.validate_connection = MagicMock(return_value=(True, {}))
|
||||||
opc_repository.client = mock_client
|
opc_repository.client = mock_client
|
||||||
mock_node = MagicMock()
|
mock_node = MagicMock()
|
||||||
opc_repository.error_count = 0
|
opc_repository.error_count = 0
|
||||||
mock_client.get_node.return_value = mock_node
|
mock_client.get_node.return_value = mock_node
|
||||||
mock_node.write_value.side_effect = Exception("Test error")
|
mock_node.write_value.side_effect = Exception("Test error")
|
||||||
opc_repository.write_data("ns=2;s=TestNode", 42.0,
|
is_success, error_data = opc_repository.write_data("ns=2;s=TestNode", 42.0,
|
||||||
"float", opc_repository.logger, metadata)
|
"float", opc_repository.logger, metadata)
|
||||||
opc_repository.validate_connection.assert_called_once()
|
opc_repository.validate_connection.assert_called_once()
|
||||||
mock_client.get_node.assert_called_once_with("ns=2;s=TestNode")
|
mock_client.get_node.assert_called_once_with("ns=2;s=TestNode")
|
||||||
mock_node.write_value.assert_called_once()
|
mock_node.write_value.assert_called_once()
|
||||||
opc_repository.notification_handler.build_and_send_notification.assert_called_once_with(
|
assert is_success is False
|
||||||
notification_id=f"OPC_WRITE_DATA_ERROR_{opc_repository.id}",
|
assert error_data['notification_id'] == f"OPC_WRITE_DATA_ERROR_{opc_repository.id}"
|
||||||
message="Failed to write data to OPC server: Test error | metadata: {'metadata': {'model_id': 'test_model', 'model_name': 'test_model', 'workflow_name': 'test_workflow', 'schema_name': 'test_schedule'}}",
|
assert error_data['message'] == "Failed to write data to OPC server: Test error | metadata: {'metadata': {'model_id': 'test_model', 'model_name': 'test_model', 'workflow_name': 'test_workflow', 'schema_name': 'test_schedule'}}"
|
||||||
block="opc_repository",
|
assert error_data['block'] == "opc_repository"
|
||||||
level=NotificationLevel.ERROR,
|
assert error_data['level'] == NotificationLevel.ERROR
|
||||||
attachment_content=ANY
|
assert error_data['attachment_content'] is not None
|
||||||
)
|
|
||||||
assert opc_repository.error_count == 1
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
from os import environ
|
from os import environ
|
||||||
from laborious.utils.connectors_config import (build_mlflow_config,
|
from laborious.utils.connectors_config import (build_mlflow_config,
|
||||||
build_opc_config,
|
build_opc_config,
|
||||||
build_postgres_config)
|
build_postgres_config,
|
||||||
|
build_mongodb_config)
|
||||||
|
|
||||||
|
|
||||||
def test_build_mlflow_config_with_env_vars():
|
def test_build_mlflow_config_with_env_vars():
|
||||||
@@ -131,3 +132,27 @@ def test_build_postgres_config_with_defaults():
|
|||||||
assert config['dbname'] == 'sientia'
|
assert config['dbname'] == 'sientia'
|
||||||
assert config['min_connections'] == 5
|
assert config['min_connections'] == 5
|
||||||
assert config['max_connections'] == 20
|
assert config['max_connections'] == 20
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_mongo_db_config_with_env_vars():
|
||||||
|
environ['MONGODB_USERNAME'] = 'sientia1'
|
||||||
|
environ['MONGODB_PASSWORD'] = 'sientia1'
|
||||||
|
environ['MONGODB_URL'] = 'localhost:27018'
|
||||||
|
environ['MONGODB_DATABASE_NAME'] = 'test_db'
|
||||||
|
|
||||||
|
assert build_mongodb_config() == {
|
||||||
|
'connection_string': 'mongodb://sientia1:sientia1@localhost:27018',
|
||||||
|
'database_name': 'test_db'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_mongo_db_config_with_defaults():
|
||||||
|
environ.pop('MONGODB_USERNAME', None)
|
||||||
|
environ.pop('MONGODB_PASSWORD', None)
|
||||||
|
environ.pop('MONGODB_DATABASE_NAME', None)
|
||||||
|
environ.pop('MONGODB_URL', None)
|
||||||
|
|
||||||
|
assert build_mongodb_config() == {
|
||||||
|
'connection_string': 'mongodb://sientia:sientia@localhost:27017',
|
||||||
|
'database_name': 'sientia'
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user