SIENTIAPDE-1974: feat(read): keep the legacy OpcManager as plan B (READ_ENGINE)
The rc3 OpcManager is restored unchanged (with its tests and scripts/generate-and-push-opc-cert.sh) for validation and as a fallback until the end of SIENTIAPDE-1974; it is removed only once it is unused and the test suite passes the same without it. - READ_ENGINE=v2 (default): ServerReader/SubscriptionEngine over the shared pool, certificate from MinIO. READ_ENGINE=legacy: the rc3 OpcManager with its own connection, slot v1 only (a v2 slot is rejected and notified) and the certificate files of the Gitea clone. An invalid value falls back to v2 with a warning. Writes/gRPC always use the pool. - pool: OPC clients carry the pod id as application/session name and product URI (as OpcManager did), so each pod's session is recognizable in the server console; application_uri stays the server_uri (certificate SAN). - README/CLAUDE.md document the plan B and how to remove it. Tests: 275 unit tests pass (restored OpcManager tests unchanged); ruff clean. Local e2e: both engines read the same slot v1 from an asyncua server and write identical documents to the same collections. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -308,3 +308,37 @@ async def test_insecure_connect_failure_keeps_cert_cache():
|
||||
await pool.get('srv', {'url': 'opc.tcp://h:4840', 'use_security': False})
|
||||
|
||||
cert_provider.invalidate.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_connect_identifies_the_pod_on_the_server():
|
||||
"""Session/application name = pod id, as the legacy OpcManager did, so each pod's
|
||||
session is recognizable in the KEPServer console."""
|
||||
pool = make_pool()
|
||||
fake_client = MagicMock(connect=AsyncMock())
|
||||
with patch('ingestor.connection.pool.Client', return_value=fake_client):
|
||||
await pool.get('srv', {'url': 'opc.tcp://h:4840', 'use_security': False})
|
||||
|
||||
assert fake_client.name == pool.pod_id
|
||||
assert fake_client.description == pool.pod_id
|
||||
assert fake_client.product_uri == pool.pod_id.replace('-', ':')
|
||||
assert fake_client.application_uri == pool.pod_id.replace('-', ':')
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_connect_server_uri_still_wins_for_application_uri():
|
||||
pool = make_pool()
|
||||
fake_client = MagicMock(connect=AsyncMock())
|
||||
with patch('ingestor.connection.pool.Client', return_value=fake_client):
|
||||
await pool.get(
|
||||
'srv',
|
||||
{
|
||||
'url': 'opc.tcp://h:4840',
|
||||
'use_security': False,
|
||||
'server_uri': 'urn:sientia:opc-ingestor',
|
||||
},
|
||||
)
|
||||
|
||||
# must match the certificate SAN URI (BadCertificateUriInvalid otherwise)
|
||||
assert fake_client.application_uri == 'urn:sientia:opc-ingestor'
|
||||
assert fake_client.name == pool.pod_id
|
||||
|
||||
Reference in New Issue
Block a user