From efddc556d37b6c61a48672ff9662df00b963f405 Mon Sep 17 00:00:00 2001 From: Sky Brewer Date: Tue, 28 Oct 2025 15:42:13 +0100 Subject: [PATCH 1/3] Test restarting channelfinder works ok --- server/tests/docker.py | 6 ++++++ server/tests/test_restart.py | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/server/tests/docker.py b/server/tests/docker.py index 455cf7a9..a786381d 100644 --- a/server/tests/docker.py +++ b/server/tests/docker.py @@ -47,3 +47,9 @@ def restart_container(compose: DockerCompose, host_name: str) -> None: docker_client = DockerClient() docker_client.containers.get(container.ID).stop() docker_client.containers.get(container.ID).start() + + +def shutdown_container(compose: DockerCompose, host_name: str) -> None: + container = compose.get_container(host_name) + docker_client = DockerClient() + docker_client.containers.get(container.ID).stop() diff --git a/server/tests/test_restart.py b/server/tests/test_restart.py index b7fbc4b1..dcda9610 100644 --- a/server/tests/test_restart.py +++ b/server/tests/test_restart.py @@ -4,8 +4,14 @@ from channelfinder import ChannelFinderClient from testcontainers.compose import DockerCompose -from .client_checks import channels_match, check_channel_property, create_client_and_wait, wait_for_sync -from .docker import restart_container, setup_compose # noqa: F401 +from .client_checks import ( + INACTIVE_PROPERTY, + channels_match, + check_channel_property, + create_client_and_wait, + wait_for_sync, +) +from .docker import restart_container, setup_compose, shutdown_container # noqa: F401 PROPERTIES_TO_MATCH = ["pvStatus", "recordType", "recordDesc", "alias", "hostName", "iocName", "recceiverID"] @@ -45,3 +51,27 @@ def test_manual_channels_same_after_restart( channels_end = cf_client.find(name="*") assert len(channels_begin) == len(channels_end) channels_match(channels_begin, channels_end, PROPERTIES_TO_MATCH + ["test_property"]) + + +def check_connection_active(cf_client: ChannelFinderClient) -> bool: + try: + cf_client.find(name="*") + return True + except Exception: + return False + + +class TestRestartChannelFinder: + def test_channels_same_after_restart(self, setup_compose: DockerCompose, cf_client: ChannelFinderClient) -> None: # noqa: F811 + channels_begin = cf_client.find(name="*") + restart_container(setup_compose, "cf") + assert wait_for_sync(cf_client, check_connection_active) + channels_end = cf_client.find(name="*") + assert len(channels_begin) == len(channels_end) + channels_match(channels_begin, channels_end, PROPERTIES_TO_MATCH) + shutdown_container(setup_compose, "ioc1-1") + assert wait_for_sync( + cf_client, lambda cf_client: check_channel_property(cf_client, "IOC1-1:Msg-I", INACTIVE_PROPERTY) + ) + channels_inactive = cf_client.find(property=[("iocName", "IOC1-1")]) + assert all(INACTIVE_PROPERTY in ch["properties"] for ch in channels_inactive) From 8fd9423bc3f2a672ee1e9a7766a0a43e288bc163 Mon Sep 17 00:00:00 2001 From: Sky Brewer Date: Wed, 29 Oct 2025 10:19:46 +0100 Subject: [PATCH 2/3] Refactor connection alive method Co-authored-by: anderslindho <44849690+anderslindho@users.noreply.github.com> --- server/tests/test_restart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/tests/test_restart.py b/server/tests/test_restart.py index dcda9610..970e66d0 100644 --- a/server/tests/test_restart.py +++ b/server/tests/test_restart.py @@ -56,9 +56,9 @@ def test_manual_channels_same_after_restart( def check_connection_active(cf_client: ChannelFinderClient) -> bool: try: cf_client.find(name="*") - return True except Exception: return False + return True class TestRestartChannelFinder: From 8fc1c7468ed9a071601cb113427208d94a8503df Mon Sep 17 00:00:00 2001 From: Sky Brewer Date: Wed, 29 Oct 2025 10:45:23 +0100 Subject: [PATCH 3/3] Cover case where ioc stops while channelfinder down --- server/tests/docker.py | 16 ++++++++++++-- server/tests/test_restart.py | 41 ++++++++++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/server/tests/docker.py b/server/tests/docker.py index a786381d..e479edcf 100644 --- a/server/tests/docker.py +++ b/server/tests/docker.py @@ -1,5 +1,6 @@ import logging from pathlib import Path +from typing import Optional import pytest from testcontainers.compose import DockerCompose @@ -42,14 +43,25 @@ def setup_compose(): compose.stop() -def restart_container(compose: DockerCompose, host_name: str) -> None: +def restart_container(compose: DockerCompose, host_name: str) -> str: container = compose.get_container(host_name) docker_client = DockerClient() docker_client.containers.get(container.ID).stop() docker_client.containers.get(container.ID).start() + return container.ID -def shutdown_container(compose: DockerCompose, host_name: str) -> None: +def shutdown_container(compose: DockerCompose, host_name: str) -> str: container = compose.get_container(host_name) docker_client = DockerClient() docker_client.containers.get(container.ID).stop() + return container.ID + + +def start_container( + compose: DockerCompose, host_name: Optional[str] = None, container_id: Optional[str] = None +) -> None: + container_id = container_id or compose.get_container(host_name).ID + if container_id: + docker_client = DockerClient() + docker_client.containers.get(container_id).start() diff --git a/server/tests/test_restart.py b/server/tests/test_restart.py index 970e66d0..fcf08e72 100644 --- a/server/tests/test_restart.py +++ b/server/tests/test_restart.py @@ -1,4 +1,5 @@ import logging +import time import pytest from channelfinder import ChannelFinderClient @@ -11,7 +12,7 @@ create_client_and_wait, wait_for_sync, ) -from .docker import restart_container, setup_compose, shutdown_container # noqa: F401 +from .docker import restart_container, setup_compose, shutdown_container, start_container # noqa: F401 PROPERTIES_TO_MATCH = ["pvStatus", "recordType", "recordDesc", "alias", "hostName", "iocName", "recceiverID"] @@ -62,16 +63,44 @@ def check_connection_active(cf_client: ChannelFinderClient) -> bool: class TestRestartChannelFinder: - def test_channels_same_after_restart(self, setup_compose: DockerCompose, cf_client: ChannelFinderClient) -> None: # noqa: F811 - channels_begin = cf_client.find(name="*") + def test_status_property_works_after_cf_restart( + self, + setup_compose: DockerCompose, # noqa: F811 + cf_client: ChannelFinderClient, + ) -> None: + # Arrange + # Act restart_container(setup_compose, "cf") assert wait_for_sync(cf_client, check_connection_active) - channels_end = cf_client.find(name="*") - assert len(channels_begin) == len(channels_end) - channels_match(channels_begin, channels_end, PROPERTIES_TO_MATCH) + + # Assert shutdown_container(setup_compose, "ioc1-1") assert wait_for_sync( cf_client, lambda cf_client: check_channel_property(cf_client, "IOC1-1:Msg-I", INACTIVE_PROPERTY) ) channels_inactive = cf_client.find(property=[("iocName", "IOC1-1")]) assert all(INACTIVE_PROPERTY in ch["properties"] for ch in channels_inactive) + + +class TestShutdownChannelFinder: + def test_status_property_works_between_cf_down( + self, + setup_compose: DockerCompose, # noqa: F811 + cf_client: ChannelFinderClient, + ) -> None: + # Arrange + cf_container_id = shutdown_container(setup_compose, "cf") + time.sleep(10) # Wait to ensure CF is down while IOC is down + + # Act + shutdown_container(setup_compose, "ioc1-1") + time.sleep(10) # Wait to ensure CF is down while IOC is down + start_container(setup_compose, container_id=cf_container_id) + assert wait_for_sync(cf_client, check_connection_active) + + # Assert + assert wait_for_sync( + cf_client, lambda cf_client: check_channel_property(cf_client, "IOC1-1:Msg-I", INACTIVE_PROPERTY) + ) + channels_inactive = cf_client.find(property=[("iocName", "IOC1-1")]) + assert all(INACTIVE_PROPERTY in ch["properties"] for ch in channels_inactive)