Swaps the legacy OpcManager read path for the gateway's SubscriptionEngine over the shared OpcConnectionPool. The OPC client certificate now always comes from MinIO + Mongo (CertProvider, Basic256Sha256) — no more certs/ shipped in the Gitea repository, so a new version branch no longer breaks the reads. - io/slots.py: parse_slot accepts slot v2 (names[]) and converts the legacy v1 (tag_name + topics; cert_path => use_security, path dropped), so gateway and Orchestrator can be deployed in any order. - managers/server_reader.py: new per-server reader with the OpcManager interface the IngestorManager already drives (connect, create_subscription, subscribe, unsubscribe, check_cycles, check_opc_listenning, shutdown). - IngestorManager owns the read path: lazy-MinIO CertProvider, the pool and a read DataSink, built without touching the network. Slots from Redis are normalized on lease and refresh; a malformed slot is notified and the last good config is kept. - GatewayRuntime borrows the pool (writes/gRPC) instead of building it, and no longer closes it on stop: a Postgres/NATS failure can't stop the reads. - pool: pin/unpin per active subscription so release_idle never evicts a subscribed connection; public evict() for lost servers / changed config. - SubscriptionEngine pins on subscribe, unpins on unsubscribe, and drops a subscription locally even when the server-side delete fails. - DataSink: model_id only written when the name has one, keeping v1 documents identical to the legacy ones. - config: CERT_BUCKET default is the legacy streamlit-connectors bucket (D7). - Removes OpcManager, its tests and scripts/generate-and-push-opc-cert.sh; README/CLAUDE.md document the MinIO certificate and the slot v2 format. Tests: 218 unit tests pass; ruff check/format clean. Local end-to-end against an asyncua server: v1 slot with two topics -> one doc per collection, legacy doc shape, idle sweep keeps the subscription, lost-server shutdown and re-initialization work. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
72 lines
1.7 KiB
Python
72 lines
1.7 KiB
Python
import pytest
|
|
|
|
from ingestor.config import GatewayConfig
|
|
|
|
_ENV_VARS = (
|
|
'NATS_URL',
|
|
'NATS_WRITE_SUBJECT',
|
|
'NATS_QUEUE',
|
|
'GRPC_ENABLED',
|
|
'GRPC_PORT',
|
|
'CERT_BUCKET',
|
|
'CERT_CACHE_DIR',
|
|
'WRITE_TIMESTAMP',
|
|
'WRITE_QUALITY',
|
|
'WRITE_MIN_PAUSE_S',
|
|
'IDLE_CONN_MAX_S',
|
|
)
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def clean_env(monkeypatch):
|
|
for var in _ENV_VARS:
|
|
monkeypatch.delenv(var, raising=False)
|
|
|
|
|
|
def test_from_env_defaults():
|
|
cfg = GatewayConfig.from_env()
|
|
|
|
assert cfg.nats_url == 'nats://localhost:4222'
|
|
assert cfg.nats_write_subject == 'opc.write'
|
|
assert cfg.nats_queue == 'gateway-writers'
|
|
assert cfg.grpc_enabled is False
|
|
assert cfg.grpc_port == 50051
|
|
assert cfg.cert_bucket == 'streamlit-connectors'
|
|
assert cfg.cert_cache_dir == '/tmp/opc-certs' # noqa: S108
|
|
assert cfg.write_timestamp is True
|
|
assert cfg.write_quality is True
|
|
assert cfg.write_min_pause_s == 0.0
|
|
assert cfg.idle_conn_max_s == 300.0
|
|
|
|
|
|
def test_from_env_overrides(monkeypatch):
|
|
monkeypatch.setenv('GRPC_ENABLED', 'true')
|
|
monkeypatch.setenv('GRPC_PORT', '6000')
|
|
monkeypatch.setenv('WRITE_MIN_PAUSE_S', '0.5')
|
|
monkeypatch.setenv('WRITE_QUALITY', 'false')
|
|
|
|
cfg = GatewayConfig.from_env()
|
|
|
|
assert cfg.grpc_enabled is True
|
|
assert cfg.grpc_port == 6000
|
|
assert cfg.write_min_pause_s == 0.5
|
|
assert cfg.write_quality is False
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
'value,expected',
|
|
[
|
|
('0', False),
|
|
('no', False),
|
|
('FALSE', False),
|
|
('1', True),
|
|
('YES', True),
|
|
],
|
|
)
|
|
def test_bool_parsing_edge_cases(monkeypatch, value, expected):
|
|
monkeypatch.setenv('GRPC_ENABLED', value)
|
|
|
|
cfg = GatewayConfig.from_env()
|
|
|
|
assert cfg.grpc_enabled is expected
|