import pytest from ingestor.io.slots import CONNECTION_FIELDS, parse_slot SECURITY = {'mode': 'SignAndEncrypt', 'policy': 'Basic256Sha256'} CERTIFICATE = { 'certificate_id': 1, 'application_uri': 'urn:sientia:opc-ingestor', 'cert': {'bucket': 'opc-certificates', 'object_name': 'client/p/cert.pem'}, 'private_key': {'bucket': 'opc-certificates', 'object_name': 'client/p/key.pem'}, } NAME = {'collection': 'c', 'tag_name': 't', 'model_name': 'm', 'model_id': '1'} RAW = { 'server1': { 'server_id': '1', 'name': 'server1', 'url': 'opc.tcp://h:4840', 'subscription_period_ms': 1000, 'security': SECURITY, 'certificate': CERTIFICATE, 'tags': { 'ns=2;i=2': { 'frequency': '15000', 'active_read': {'enabled': True, 'cycle_multiple': 3}, 'names': [ { 'collection': 'raw_x', 'tag_name': 'Counter', 'model_name': 'm1', 'model_id': '1', }, { 'collection': 'raw_y', 'tag_name': 'Contador', 'model_name': 'm2', 'model_id': '2', }, ], } }, } } def _server(**fields): server = { 'server_id': '1', 'url': 'u', 'security': {'mode': 'None', 'policy': 'None'}, 'certificate': None, 'tags': {'ns=2;i=1': {'frequency': '1000', 'names': [NAME]}}, } return {'s': {**server, **fields}} def test_parse_slot_multi_name(): slot = parse_slot(RAW) tag = slot['server1']['tags']['ns=2;i=2'] assert len(tag['names']) == 2 assert tag['active_read']['cycle_multiple'] == 3 def test_parse_slot_keeps_security_and_certificate(): server = parse_slot(RAW)['server1'] assert server['security'] == SECURITY assert server['certificate'] == CERTIFICATE assert {field: server[field] for field in CONNECTION_FIELDS} == { 'url': 'opc.tcp://h:4840', 'subscription_period_ms': 1000, 'security': SECURITY, 'certificate': CERTIFICATE, } def test_parse_slot_without_certificate_key_means_no_certificate(): raw = _server() del raw['s']['certificate'] server = parse_slot(raw)['s'] assert server['certificate'] is None assert server['name'] == 's' # falls back to the slot key def test_parse_slot_defaults_active_read_disabled(): tag = parse_slot(_server())['s']['tags']['ns=2;i=1'] assert tag['active_read'] == {'enabled': False} @pytest.mark.parametrize( 'raw', [ pytest.param(_server(tags={'ns=2;i=1': {'frequency': '1000'}}), id='tag-without-names'), pytest.param( _server(tags={'ns=2;i=1': {'frequency': '1', 'names': [{'collection': 'c'}]}}), id='name-without-tag-name', ), pytest.param( _server( tags={ 'ns=2;i=1': { 'frequency': '1', 'names': [{'collection': 'c', 'tag_name': 't'}], } } ), id='name-without-model-id', ), pytest.param(_server(security=None), id='no-security'), # Slot v1 (an Orchestrator before SIENTIAPDE-1974): no longer accepted pytest.param( { 'kepserver': { 'server_id': '1', 'url': 'opc.tcp://kepserver:49320', 'server_uri': 'urn:sientia:opc-ingestor', 'cert_path': '/app/certs/opc-ingestor-cert.pem', 'tags': { 'ns=2;s=A': {'tag_name': 'A', 'frequency': 30000, 'topics': ['raw_x']} }, } }, id='slot-v1', ), ], ) def test_parse_slot_rejects_invalid_slots(raw): with pytest.raises((KeyError, ValueError)): parse_slot(raw)