Files
sientia-dataops-opc-ingestor/tests/unit/adapters/test_grpc_server.py
2026-07-15 08:39:54 -03:00

97 lines
3.1 KiB
Python

from unittest.mock import AsyncMock, MagicMock
import grpc
import pytest
from ingestor.adapters.grpc_server import GrpcServer, ReadTagServicer
from ingestor.proto.opc_gateway_pb2 import ReadTagRequest
def make_request(server_id='srv1', addr='ns=2;i=5'):
return ReadTagRequest(server_id=server_id, addr=addr, data_type='float')
@pytest.mark.asyncio
async def test_read_tag_maps_full_result_onto_response():
active_read = AsyncMock()
active_read.read_now.return_value = {
'value': 1.5,
'opc_status_code': 'Good',
'source_timestamp': '2026-07-15T10:00:00-03:00',
'server_timestamp': '2026-07-15T10:00:01-03:00',
'persisted': False,
}
servicer = ReadTagServicer(active_read, MagicMock())
response = await servicer.ReadTag(make_request(), AsyncMock())
assert response.value == '1.5'
assert response.opc_status_code == 'Good'
assert response.source_timestamp == '2026-07-15T10:00:00-03:00'
assert response.server_timestamp == '2026-07-15T10:00:01-03:00'
assert response.persisted is False
@pytest.mark.asyncio
async def test_read_tag_none_timestamps_become_empty_string():
active_read = AsyncMock()
active_read.read_now.return_value = {
'value': 1.5,
'opc_status_code': None,
'source_timestamp': None,
'server_timestamp': None,
'persisted': False,
}
servicer = ReadTagServicer(active_read, MagicMock())
response = await servicer.ReadTag(make_request(), AsyncMock())
assert response.opc_status_code == ''
assert response.source_timestamp == ''
assert response.server_timestamp == ''
@pytest.mark.asyncio
async def test_read_tag_aborts_with_internal_on_engine_failure():
active_read = AsyncMock()
active_read.read_now.side_effect = RuntimeError('boom')
logger = MagicMock()
servicer = ReadTagServicer(active_read, logger)
context = AsyncMock()
context.abort.side_effect = grpc.RpcError('aborted')
with pytest.raises(grpc.RpcError):
await servicer.ReadTag(make_request(), context)
context.abort.assert_awaited_once()
args = context.abort.call_args.args
assert args[0] == grpc.StatusCode.INTERNAL
logger.error.assert_called_once()
@pytest.mark.asyncio
async def test_read_tag_uses_slot_lookup_names_when_provided():
active_read = AsyncMock()
active_read.read_now.return_value = {
'value': 1,
'opc_status_code': 'Good',
'source_timestamp': None,
'server_timestamp': None,
'persisted': True,
}
names = [{'collection': 'c1', 'name': 't1'}]
slot_lookup = MagicMock(return_value=names)
servicer = ReadTagServicer(active_read, MagicMock(), slot_lookup=slot_lookup)
await servicer.ReadTag(make_request(server_id='srv1', addr='ns=2;i=5'), AsyncMock())
slot_lookup.assert_called_once_with('srv1', 'ns=2;i=5')
active_read.read_now.assert_awaited_once_with('srv1', 'ns=2;i=5', names=names)
@pytest.mark.asyncio
async def test_grpc_server_stop_before_start_does_not_raise():
server = GrpcServer(active_read=AsyncMock(), logger=MagicMock())
await server.stop() # no raise