diff --git a/tests/laborious/activities/test_opc.py b/tests/laborious/activities/test_opc.py index ebce052..6540a16 100644 --- a/tests/laborious/activities/test_opc.py +++ b/tests/laborious/activities/test_opc.py @@ -16,11 +16,28 @@ metadata = { @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() - server1 = MagicMock() - server2 = MagicMock() - mock_opc_repository.side_effect = [server1, server2] + server1 = MagicMock( + connect=MagicMock(return_value=(True, {})), + 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() servers = { 'server1': { @@ -40,6 +57,15 @@ def test___init__(mock_opc_repository): 'private_key_path': '', 'server_cert_path': '', '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( @@ -84,6 +110,22 @@ def test___init__(mock_opc_repository): server1.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 @patch("laborious.activities.opc.OpcRepository") @@ -99,8 +141,12 @@ def opc(mock_opc_repository): '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_servers=servers, @@ -128,6 +174,28 @@ def test_write_data_success(opc, tag, data_type, data): 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): opc.opc_repository['server1'].write_data.side_effect = Exception( "Test error") diff --git a/tests/laborious/utils/repository/test_opc_repository.py b/tests/laborious/utils/repository/test_opc_repository.py index 1b661d2..c399139 100644 --- a/tests/laborious/utils/repository/test_opc_repository.py +++ b/tests/laborious/utils/repository/test_opc_repository.py @@ -115,17 +115,15 @@ def test_try_connect_fail(opc_repository): opc_repository.client = MagicMock() 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() - assert opc_repository.last_reconnection_time is not None - opc_repository.notification_handler.build_and_send_notification.assert_called_once_with( - notification_id=f"OPC_CONNECTION_ERROR_{opc_repository.id}", - message="Failed to connect to OPC server: Test error", - block="opc_repository", - level=NotificationLevel.ERROR, - attachment_content=ANY - ) + assert is_connected is False + assert error_data['notification_id'] == f"OPC_CONNECTION_ERROR_{opc_repository.id}" + assert error_data['message'] == "Failed to connect to OPC server: Test error" + assert error_data['block'] == "opc_repository" + assert error_data['level'] == NotificationLevel.ERROR + assert error_data['attachment_content'] is not None 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() opc_repository.try_connect.assert_not_called() - assert response is False + assert response == (False, {}) @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 output = opc_repository.validate_connection() - assert output is True + assert output == (True, {}) 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.write_data("ns=2;s=TestNode", 42.0, "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): - opc_repository.validate_connection = MagicMock(return_value=False) + opc_repository.validate_connection = MagicMock(return_value=(False, {})) opc_repository.client = MagicMock() opc_repository.error_count = 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): - opc_repository.validate_connection = MagicMock(return_value=True) + opc_repository.validate_connection = MagicMock(return_value=(True, {})) opc_repository.client = MagicMock() opc_repository.error_count = 0 opc_repository.client.get_node.side_effect = Exception("Test error") - opc_repository.write_data("ns=2;s=TestNode", 42.0, - "float", opc_repository.logger, metadata) + is_success, error_data = opc_repository.write_data("ns=2;s=TestNode", 42.0, + "float", opc_repository.logger, metadata) opc_repository.validate_connection.assert_called_once() 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( - 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'}}", - block="opc_repository", - level=NotificationLevel.ERROR, - attachment_content=ANY - ) - assert opc_repository.error_count == 1 + assert is_success is False + assert error_data['notification_id'] == f"OPC_WRITE_GET_NODE_ERROR_{opc_repository.id}" + 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'}}" + assert error_data['block'] == "opc_repository" + assert error_data['level'] == NotificationLevel.ERROR + assert error_data['attachment_content'] is not None 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 mock_node = MagicMock() mock_client.get_node.return_value = mock_node - opc_repository.write_data("ns=2;s=TestNode", 42.0, - "invalid_type", opc_repository.logger, metadata) + is_success, error_data = opc_repository.write_data("ns=2;s=TestNode", 42.0, + "invalid_type", opc_repository.logger, metadata) opc_repository.validate_connection.assert_called_once() mock_client.get_node.assert_called_once_with("ns=2;s=TestNode") - opc_repository.notification_handler.build_and_send_notification.assert_called_once_with( - 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'}}", - block="opc_repository", - level=NotificationLevel.ERROR - ) + assert is_success is False + assert error_data['notification_id'] == f"OPC_WRITE_DATA_TYPE_ERROR_{opc_repository.id}" + 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'}}" + assert error_data['block'] == "opc_repository" + assert error_data['level'] == NotificationLevel.ERROR + assert error_data.get('attachment_content') is None 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 mock_node = MagicMock() 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): - opc_repository.validate_connection = MagicMock(return_value=True) + opc_repository.validate_connection = MagicMock(return_value=(True, {})) opc_repository.client = mock_client mock_node = MagicMock() opc_repository.error_count = 0 mock_client.get_node.return_value = mock_node mock_node.write_value.side_effect = Exception("Test error") - opc_repository.write_data("ns=2;s=TestNode", 42.0, - "float", opc_repository.logger, metadata) + is_success, error_data = opc_repository.write_data("ns=2;s=TestNode", 42.0, + "float", opc_repository.logger, metadata) opc_repository.validate_connection.assert_called_once() mock_client.get_node.assert_called_once_with("ns=2;s=TestNode") mock_node.write_value.assert_called_once() - opc_repository.notification_handler.build_and_send_notification.assert_called_once_with( - 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'}}", - block="opc_repository", - level=NotificationLevel.ERROR, - attachment_content=ANY - ) - assert opc_repository.error_count == 1 + assert is_success is False + assert error_data['notification_id'] == f"OPC_WRITE_DATA_ERROR_{opc_repository.id}" + 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'}}" + assert error_data['block'] == "opc_repository" + assert error_data['level'] == NotificationLevel.ERROR + assert error_data['attachment_content'] is not None diff --git a/tests/laborious/utils/test_connectors_config.py b/tests/laborious/utils/test_connectors_config.py index a7b36aa..acb5c21 100644 --- a/tests/laborious/utils/test_connectors_config.py +++ b/tests/laborious/utils/test_connectors_config.py @@ -1,7 +1,8 @@ from os import environ from laborious.utils.connectors_config import (build_mlflow_config, build_opc_config, - build_postgres_config) + build_postgres_config, + build_mongodb_config) 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['min_connections'] == 5 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' + }