SIENTIAPDE-988 Implement core functionality for OPC ingestor, including main execution flow, IngestorManager methods, and OPC server management. Add unit tests for IngestorManager and OPCManager.
This commit is contained in:
227
tests/managers/test_ingestor_manager.py
Normal file
227
tests/managers/test_ingestor_manager.py
Normal file
@@ -0,0 +1,227 @@
|
||||
from unittest.mock import MagicMock, patch
|
||||
from pytest import fixture
|
||||
|
||||
from ingestor.managers.ingestor_manager import IngestorManager
|
||||
|
||||
|
||||
@fixture
|
||||
@patch('ingestor.managers.ingestor_manager.DataManager')
|
||||
@patch('ingestor.managers.ingestor_manager.ResourceManager')
|
||||
def ingestor_manager(data_manager_mock, resource_manager_mock):
|
||||
return IngestorManager(
|
||||
kafka_servers="localhost:9092",
|
||||
redis_host="localhost",
|
||||
redis_port=6379,
|
||||
lease_ttl=60,
|
||||
heartbeat_ttl=60,
|
||||
pod_id="test_pod",
|
||||
number_of_ingestors=3,
|
||||
poll_interval=5,
|
||||
logger=MagicMock()
|
||||
)
|
||||
|
||||
|
||||
@patch('ingestor.managers.ingestor_manager.OpcManager')
|
||||
@patch('ingestor.managers.ingestor_manager.DataManager')
|
||||
@patch('ingestor.managers.ingestor_manager.ResourceManager')
|
||||
def test___init__(resource_manager_mock, data_manager_mock, opc_manager_mock):
|
||||
|
||||
ingestor = IngestorManager(
|
||||
kafka_servers="localhost:9092",
|
||||
redis_host="localhost",
|
||||
redis_port=6379,
|
||||
lease_ttl=60,
|
||||
heartbeat_ttl=60,
|
||||
pod_id="test_pod",
|
||||
number_of_ingestors=3,
|
||||
poll_interval=5,
|
||||
logger=MagicMock()
|
||||
)
|
||||
|
||||
opc_manager_mock.assert_not_called()
|
||||
data_manager_mock.assert_called_once_with(
|
||||
"localhost:9092", ingestor.logger)
|
||||
resource_manager_mock.assert_called_once_with(
|
||||
"localhost", 6379, 60, 60, "test_pod")
|
||||
|
||||
assert ingestor.number_of_ingestors == 3
|
||||
assert ingestor.poll_interval == 5
|
||||
assert ingestor.managed_tags == {}
|
||||
assert ingestor.opc_servers == {}
|
||||
assert ingestor.opc_managers == {}
|
||||
assert ingestor.data_manager == data_manager_mock.return_value
|
||||
assert ingestor.resource_manager == resource_manager_mock.return_value
|
||||
|
||||
|
||||
@patch('ingestor.managers.ingestor_manager.OpcManager')
|
||||
def test_update_opc_servers(opc_manager, ingestor_manager):
|
||||
manager1 = MagicMock()
|
||||
manager2 = MagicMock()
|
||||
manager3 = MagicMock()
|
||||
|
||||
def mock_initialize_from_config(config, data_manager, logger):
|
||||
if config == {"config": "config1"}:
|
||||
return manager1
|
||||
elif config == {"config": "config2"}:
|
||||
return manager2
|
||||
elif config == {"config": "config3"}:
|
||||
return manager3
|
||||
|
||||
opc_manager.initialize_from_config = MagicMock(
|
||||
side_effect=mock_initialize_from_config
|
||||
)
|
||||
|
||||
ingestor_manager.managed_tags = {
|
||||
"slot1": {
|
||||
"server1": {"config": "config1"},
|
||||
"server2": {"config": "config2"}
|
||||
},
|
||||
"slot2": {
|
||||
"server3": {"config": "config3"},
|
||||
"server1": {"config": "config1"}
|
||||
}
|
||||
}
|
||||
|
||||
ingestor_manager.opc_servers = {
|
||||
"server3": {"config": "config3"},
|
||||
"server2": {"old_config": "old_config2"}
|
||||
}
|
||||
|
||||
mock = MagicMock()
|
||||
ingestor_manager.opc_managers['server3'] = MagicMock()
|
||||
ingestor_manager.opc_managers['server2'] = mock
|
||||
ingestor_manager.update_opc_servers()
|
||||
|
||||
assert len(ingestor_manager.opc_managers) == 3
|
||||
assert len(ingestor_manager.opc_servers) == 3
|
||||
|
||||
opc_manager.initialize_from_config.assert_any_call(
|
||||
{"config": "config1"}, ingestor_manager.data_manager, ingestor_manager.logger)
|
||||
opc_manager.initialize_from_config.assert_any_call(
|
||||
{"config": "config2"}, ingestor_manager.data_manager, ingestor_manager.logger)
|
||||
|
||||
ingestor_manager.opc_managers['server1'].connect.assert_called_once()
|
||||
ingestor_manager.opc_managers['server2'].connect.assert_called_once()
|
||||
ingestor_manager.opc_managers['server3'].connect.assert_not_called()
|
||||
|
||||
assert ingestor_manager.opc_servers['server1'] == {"config": "config1"}
|
||||
assert ingestor_manager.opc_servers['server2'] == {"config": "config2"}
|
||||
assert ingestor_manager.opc_servers['server3'] == {"config": "config3"}
|
||||
|
||||
assert ingestor_manager.opc_managers['server2'] != mock
|
||||
|
||||
|
||||
def test_declare_active(ingestor_manager):
|
||||
ingestor_manager.resource_manager.ingestor_heartbeat = MagicMock()
|
||||
ingestor_manager.declare_active()
|
||||
ingestor_manager.resource_manager.ingestor_heartbeat.assert_called_once()
|
||||
|
||||
|
||||
def test_get_active_ingestors(ingestor_manager):
|
||||
ingestor_manager.resource_manager.get_all_ingestors = MagicMock()
|
||||
ingestor_manager.get_active_ingestors()
|
||||
ingestor_manager.resource_manager.get_all_ingestors.assert_called_once()
|
||||
|
||||
|
||||
def test_get_slot_leases_1_success(ingestor_manager):
|
||||
ingestor_manager.resource_manager.lease_tag = MagicMock(
|
||||
return_value=True)
|
||||
ingestor_manager.resource_manager.get_tag_slot = MagicMock(
|
||||
return_value={"tags": ["tag1"]})
|
||||
|
||||
result = ingestor_manager.get_slot_leases()
|
||||
|
||||
assert result == {
|
||||
"1": {"tags": ["tag1"]}
|
||||
}
|
||||
|
||||
|
||||
def test_get_slot_leases_2_success(ingestor_manager):
|
||||
ingestor_manager.resource_manager.lease_tag = MagicMock(
|
||||
side_effect=[True, True])
|
||||
ingestor_manager.resource_manager.get_tag_slot = MagicMock(
|
||||
side_effect=[{"tags": ["tag1"]}, {"tags": ["tag2"]}])
|
||||
|
||||
result = ingestor_manager.get_slot_leases(max_slots=2)
|
||||
|
||||
assert result == {
|
||||
"1": {"tags": ["tag1"]},
|
||||
"2": {"tags": ["tag2"]}
|
||||
}
|
||||
|
||||
|
||||
def test_get_slot_leases_1_failure(ingestor_manager):
|
||||
ingestor_manager.resource_manager.lease_tag = MagicMock(
|
||||
return_value=False)
|
||||
ingestor_manager.resource_manager.get_tag_slot = MagicMock(
|
||||
return_value={"tags": ["tag1"]})
|
||||
|
||||
result = ingestor_manager.get_slot_leases()
|
||||
ingestor_manager.resource_manager.get_tag_slot.assert_not_called()
|
||||
|
||||
assert result == {}
|
||||
|
||||
|
||||
def test_update_slot_config(ingestor_manager):
|
||||
ingestor_manager.managed_tags = {
|
||||
"slot1": {"config": "old_config"},
|
||||
"slot2": {"config": "new_config"}
|
||||
}
|
||||
|
||||
ingestor_manager.resource_manager.get_tag_slot = MagicMock(
|
||||
side_effect=[
|
||||
{"config": "updated_config"},
|
||||
{"config": "new_config"}
|
||||
]
|
||||
)
|
||||
|
||||
ingestor_manager.update_opc_servers = MagicMock()
|
||||
ingestor_manager.subscribe_to_tags = MagicMock()
|
||||
|
||||
ingestor_manager.update_slot_config()
|
||||
|
||||
assert ingestor_manager.managed_tags["slot1"] == {
|
||||
"config": "updated_config"}
|
||||
assert ingestor_manager.managed_tags["slot2"] == {
|
||||
"config": "new_config"}
|
||||
|
||||
ingestor_manager.update_opc_servers.assert_called_once()
|
||||
ingestor_manager.subscribe_to_tags.assert_called_once_with(
|
||||
{"config": "updated_config"}
|
||||
)
|
||||
|
||||
|
||||
def test_drop_slot_leases(ingestor_manager):
|
||||
ingestor_manager.resource_manager.drop_tag_lease = MagicMock()
|
||||
ingestor_manager.drop_slot_leases(["1", "2"])
|
||||
|
||||
ingestor_manager.resource_manager.drop_tag_lease.assert_any_call("1")
|
||||
ingestor_manager.resource_manager.drop_tag_lease.assert_any_call("2")
|
||||
|
||||
|
||||
def test_subscribe_to_tags(ingestor_manager):
|
||||
ingestor_manager.opc_managers = {
|
||||
"server1": MagicMock(),
|
||||
"server2": MagicMock()
|
||||
}
|
||||
ingestor_manager.subscriptions = {
|
||||
"server1": MagicMock()
|
||||
}
|
||||
tags = {
|
||||
'slot1': {
|
||||
"server1": {"tags": "config1"},
|
||||
"server2": {"tags": "config2"},
|
||||
'server3': {"tags": "config3"}
|
||||
}
|
||||
}
|
||||
|
||||
ingestor_manager.subscribe_to_tags(tags)
|
||||
|
||||
ingestor_manager.opc_managers["server1"].create_subscription.assert_called_once_with(
|
||||
'slot1')
|
||||
|
||||
ingestor_manager.opc_managers["server1"].subscribe.assert_called_once_with(
|
||||
'slot1', 'config1', ingestor_manager.poll_interval)
|
||||
ingestor_manager.opc_managers["server2"].subscribe.assert_called_once_with(
|
||||
'slot1', 'config2', ingestor_manager.poll_interval)
|
||||
ingestor_manager.opc_managers.get("server3") is None
|
||||
@@ -51,7 +51,7 @@ def opc_manager(raw_opc_manager):
|
||||
|
||||
@fixture
|
||||
def opc_manager_subscribed(opc_manager):
|
||||
opc_manager.subscription = MagicMock()
|
||||
opc_manager.subscriptions['sub1'] = MagicMock()
|
||||
|
||||
return opc_manager
|
||||
|
||||
@@ -114,7 +114,7 @@ def test_connect_with_security(client, raw_opc_manager):
|
||||
|
||||
def test_create_subscription_no_client(raw_opc_manager):
|
||||
try:
|
||||
raw_opc_manager.create_subscription()
|
||||
raw_opc_manager.create_subscription('sub1')
|
||||
except ValueError as e:
|
||||
assert str(e) == "Client not connected. Call connect first."
|
||||
else:
|
||||
@@ -122,26 +122,24 @@ def test_create_subscription_no_client(raw_opc_manager):
|
||||
|
||||
|
||||
def test_create_subscription_success_has_period(opc_manager):
|
||||
opc_manager.create_subscription(1000)
|
||||
opc_manager.create_subscription('sub1', 1000)
|
||||
|
||||
assert opc_manager.period == 1000
|
||||
opc_manager.client.create_subscription.assert_called_once_with(
|
||||
1000, opc_manager)
|
||||
assert opc_manager.subscription is not None
|
||||
assert opc_manager.subscriptions['sub1'] is not None
|
||||
|
||||
|
||||
def test_create_subscription_success_no_period(opc_manager):
|
||||
opc_manager.create_subscription(None)
|
||||
opc_manager.create_subscription('sub1', None)
|
||||
|
||||
assert opc_manager.period == 500
|
||||
opc_manager.client.create_subscription.assert_called_once_with(
|
||||
500, opc_manager)
|
||||
assert opc_manager.subscription is not None
|
||||
assert opc_manager.subscriptions['sub1'] is not None
|
||||
|
||||
|
||||
def test_subscribe_no_subscription(opc_manager):
|
||||
try:
|
||||
opc_manager.subscribe(tags, 1000)
|
||||
opc_manager.subscribe('sub1', tags, 1000)
|
||||
except ValueError as e:
|
||||
assert str(
|
||||
e) == "Subscription not created. Call create_subscription first."
|
||||
@@ -160,42 +158,45 @@ def test_subscribe_success(opc_manager_subscribed):
|
||||
opc_manager_subscribed.client.get_node(n) for n in tags if n != 'ns=3;i=1001']
|
||||
|
||||
|
||||
def test_unsubscribe_no_subscription(opc_manager):
|
||||
try:
|
||||
opc_manager.unsubscribe('sub1')
|
||||
except ValueError as e:
|
||||
assert str(
|
||||
e) == "Subscription not created. Call create_subscription first."
|
||||
else:
|
||||
assert False, "ValueError not raised"
|
||||
|
||||
|
||||
def test_unsubscribe_success(opc_manager_subscribed):
|
||||
opc_manager_subscribed.unsubscribe('sub1')
|
||||
|
||||
opc_manager_subscribed.subscriptions.get('sub1') is None
|
||||
|
||||
|
||||
def test_disconnect_success(opc_manager_subscribed):
|
||||
opc_manager_subscribed.client = MagicMock()
|
||||
opc_manager_subscribed.subscription = MagicMock()
|
||||
|
||||
opc_manager_subscribed.disconnect()
|
||||
|
||||
opc_manager_subscribed.subscription.delete.assert_called_once()
|
||||
opc_manager_subscribed.subscriptions['sub1'].delete.assert_called_once()
|
||||
opc_manager_subscribed.client.disconnect.assert_called_once()
|
||||
|
||||
|
||||
def test_disconnect_error(opc_manager_subscribed):
|
||||
opc_manager_subscribed.client = MagicMock()
|
||||
opc_manager_subscribed.subscription = MagicMock(
|
||||
opc_manager_subscribed.subscriptions['sub1'] = MagicMock(
|
||||
delete=MagicMock(side_effect=Exception("Test error"))
|
||||
)
|
||||
|
||||
opc_manager_subscribed.disconnect()
|
||||
|
||||
opc_manager_subscribed.subscription.delete.assert_called_once()
|
||||
opc_manager_subscribed.subscriptions['sub1'].delete.assert_called_once()
|
||||
opc_manager_subscribed.client.disconnect.assert_not_called()
|
||||
opc_manager_subscribed.logger.error.assert_called_once_with(
|
||||
"Failed to clean up subscription: Test error")
|
||||
|
||||
|
||||
def test_init_collector(opc_manager_subscribed):
|
||||
opc_manager_subscribed.connect = MagicMock()
|
||||
opc_manager_subscribed.create_subscription = MagicMock()
|
||||
opc_manager_subscribed.subscribe = MagicMock()
|
||||
|
||||
opc_manager_subscribed.init_collector(tags, 1000, 500)
|
||||
|
||||
opc_manager_subscribed.connect.assert_called_once()
|
||||
opc_manager_subscribed.create_subscription.assert_called_once_with(500)
|
||||
opc_manager_subscribed.subscribe.assert_called_once_with(tags, 1000)
|
||||
|
||||
|
||||
def test_datachange_notification(opc_manager_subscribed):
|
||||
data = MagicMock(
|
||||
monitored_item=MagicMock(
|
||||
|
||||
@@ -43,7 +43,8 @@ def test_ingestor_heartbeat(resource_manager):
|
||||
|
||||
def test_lease_tag(resource_manager):
|
||||
resource_manager.redis.set.return_value = True
|
||||
resource_manager.lease_tag('tag_id')
|
||||
output = resource_manager.lease_tag('tag_id')
|
||||
assert output is True
|
||||
resource_manager.redis.set.assert_called_once_with(
|
||||
'lease:opc_tags:tag_id', 'pod_id', nx=True, ex=10
|
||||
)
|
||||
@@ -71,3 +72,11 @@ def test_renew_tag_lease_failure(resource_manager):
|
||||
'lease:opc_tags:tag_id'
|
||||
)
|
||||
resource_manager.redis.expire.assert_not_called()
|
||||
|
||||
|
||||
def test_drop_tag_lease(resource_manager):
|
||||
resource_manager.redis.delete.return_value = True
|
||||
resource_manager.drop_tag_lease('tag_id')
|
||||
resource_manager.redis.delete.assert_called_once_with(
|
||||
'lease:opc_tags:tag_id'
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user