diff --git a/server/tests/client_checks.py b/server/tests/client_checks.py index a5bda1e..4e1f9f2 100644 --- a/server/tests/client_checks.py +++ b/server/tests/client_checks.py @@ -13,6 +13,10 @@ TIME_PERIOD_INCREMENT = 2 DEFAULT_CHANNEL_NAME = "IOC1-1:ai:test" +BASE_ALIAS_COUNT = 1 +BASE_RECORD_COUNT = 1 +BASE_IOC_CHANNEL_COUNT = BASE_ALIAS_COUNT + BASE_RECORD_COUNT + def channel_match(channel0, channel1, properties_to_match: list[str]): assert channel0["name"] == channel1["name"] diff --git a/server/tests/ioc/test_remove_infotag.db b/server/tests/ioc/test_remove_alias_after.db similarity index 72% rename from server/tests/ioc/test_remove_infotag.db rename to server/tests/ioc/test_remove_alias_after.db index 5ee53d2..9b44e57 100644 --- a/server/tests/ioc/test_remove_infotag.db +++ b/server/tests/ioc/test_remove_alias_after.db @@ -1,6 +1,6 @@ record(ai, "$(P)ai:test") { - alias("$(P)ai:test:alias") info("test", "testing") + info("archive", "MONITOR@1") field(DESC, "testdesc") } diff --git a/server/tests/ioc/test_remove_channel_after.db b/server/tests/ioc/test_remove_channel_after.db new file mode 100644 index 0000000..8ca3937 --- /dev/null +++ b/server/tests/ioc/test_remove_channel_after.db @@ -0,0 +1,3 @@ + +record(ai, "$(P)ai:test") { +} diff --git a/server/tests/ioc/test_remove_channel_before.db b/server/tests/ioc/test_remove_channel_before.db new file mode 100644 index 0000000..bf33b35 --- /dev/null +++ b/server/tests/ioc/test_remove_channel_before.db @@ -0,0 +1,6 @@ + +record(ai, "$(P)ai:test") { +} + +record(ai, "$(P)ai:test-2") { +} diff --git a/server/tests/ioc/test_remove_infotag_after.db b/server/tests/ioc/test_remove_infotag_after.db new file mode 100644 index 0000000..8ca3937 --- /dev/null +++ b/server/tests/ioc/test_remove_infotag_after.db @@ -0,0 +1,3 @@ + +record(ai, "$(P)ai:test") { +} diff --git a/server/tests/ioc/test_remove_infotag_before.db b/server/tests/ioc/test_remove_infotag_before.db new file mode 100644 index 0000000..795424d --- /dev/null +++ b/server/tests/ioc/test_remove_infotag_before.db @@ -0,0 +1,4 @@ + +record(ai, "$(P)ai:test") { + info("archive", "testing") +} diff --git a/server/tests/test_bash_ioc.py b/server/tests/test_bash_ioc.py index 238e3d4..c91c433 100644 --- a/server/tests/test_bash_ioc.py +++ b/server/tests/test_bash_ioc.py @@ -3,12 +3,14 @@ from pathlib import Path from typing import Optional +from channelfinder import ChannelFinderClient from testcontainers.compose import DockerCompose from docker import DockerClient from docker.models.containers import Container from .client_checks import ( + BASE_IOC_CHANNEL_COUNT, DEFAULT_CHANNEL_NAME, INACTIVE_PROPERTY, check_channel_property, @@ -46,43 +48,108 @@ def stream_logs(exec_result, cmd: str): log_thread.start() -class TestRemoveProperty: - def test_remove_property(self, setup_compose: DockerCompose) -> None: # noqa: F811 +def start_ioc(setup_compose: DockerCompose, db_file: Optional[str] = None) -> Container: + ioc_container = setup_compose.get_container("ioc1-1") + docker_client = DockerClient() + docker_ioc = docker_client.containers.get(ioc_container.ID) + docker_exec_new_command(docker_ioc, "./demo /ioc/st.cmd", env={"DB_FILE": db_file} if db_file else None) + return docker_ioc + + +def restart_ioc( + ioc_container: Container, cf_client: ChannelFinderClient, channel_name: str, new_db_file: str +) -> Container: + ioc_container.stop() + LOG.info("Waiting for channels to go inactive") + assert wait_for_sync( + cf_client, + lambda cf_client: check_channel_property(cf_client, name=channel_name, prop=INACTIVE_PROPERTY), + ) + ioc_container.start() + + docker_exec_new_command(ioc_container, "./demo /ioc/st.cmd", env={"DB_FILE": new_db_file}) + # Detach by not waiting for the thread to finish + + LOG.debug("ioc1-1 restart") + assert wait_for_sync(cf_client, lambda cf_client: check_channel_property(cf_client, name=channel_name)), ( + "ioc1-1 failed to restart and sync" + ) + + +class TestRemoveInfoTag: + def test_remove_infotag(self, setup_compose: DockerCompose) -> None: """ - Test that the setup in the docker compose creates channels in channelfinder + Test that removing an infotag from a record works """ - ioc_container = setup_compose.get_container("ioc1-1") - docker_client = DockerClient() - docker_ioc = docker_client.containers.get(ioc_container.ID) - docker_exec_new_command(docker_ioc, "./demo /ioc/st.cmd") - + test_channel_count = 1 + # Arrange + docker_ioc = start_ioc(setup_compose, db_file="test_remove_infotag_before.db") LOG.info("Waiting for channels to sync") - cf_client = create_client_and_wait(setup_compose, expected_channel_count=2) + cf_client = create_client_and_wait(setup_compose, expected_channel_count=test_channel_count) # Check ioc1-1 has ai:test with info tag "archive" LOG.debug('Checking ioc1-1 has ai:test with info tag "archive"') - channel = cf_client.find(name=DEFAULT_CHANNEL_NAME) + channels = cf_client.find(name=DEFAULT_CHANNEL_NAME) + TEST_INFO_TAG = {"name": "archive", "owner": "admin", "value": "testing", "channels": []} - def get_len_archive_properties(channel): - return len([prop for prop in channel[0]["properties"] if prop["name"] == "archive"]) + assert any(TEST_INFO_TAG in ch["properties"] for ch in channels), ( + "Info tag 'archive' not found in channel before removal" + ) - assert get_len_archive_properties(channel) == 1 + # Act + restart_ioc(docker_ioc, cf_client, DEFAULT_CHANNEL_NAME, "test_remove_infotag_after.db") - docker_ioc.stop() - LOG.info("Waiting for channels to go inactive") - assert wait_for_sync( - cf_client, - lambda cf_client: check_channel_property(cf_client, name=DEFAULT_CHANNEL_NAME, prop=INACTIVE_PROPERTY), + # Assert + channels = cf_client.find(name=DEFAULT_CHANNEL_NAME) + LOG.debug("archive channels: %s", channels) + assert all(TEST_INFO_TAG not in ch["properties"] for ch in channels), ( + "Info tag 'archive' still found in channel after removal" ) - docker_ioc.start() - docker_exec_new_command(docker_ioc, "./demo /ioc/st.cmd", env={"DB_FILE": "test_remove_infotag.db"}) - # Detach by not waiting for the thread to finish - LOG.debug("ioc1-1 restart") - assert wait_for_sync(cf_client, lambda cf_client: check_channel_property(cf_client, name=DEFAULT_CHANNEL_NAME)) - LOG.debug("ioc1-1 has restarted and synced") +class TestRemoveChannel: + def test_remove_channel(self, setup_compose: DockerCompose) -> None: # noqa: F811 + """ + Test that removing a channel works correctly. + """ + # Arrange + docker_ioc = start_ioc(setup_compose, db_file="test_remove_channel_before.db") + LOG.info("Waiting for channels to sync") + cf_client = create_client_and_wait(setup_compose, expected_channel_count=2) + + # Check ioc1-1 has base channel + LOG.debug("Checking ioc1-1 has both channels before removal") + check_channel_property(cf_client, name=DEFAULT_CHANNEL_NAME) + second_channel_name = f"{DEFAULT_CHANNEL_NAME}-2" + check_channel_property(cf_client, name=second_channel_name) + + # Act + restart_ioc(docker_ioc, cf_client, DEFAULT_CHANNEL_NAME, "test_remove_channel_after.db") + + # Assert + check_channel_property(cf_client, name=second_channel_name, prop=INACTIVE_PROPERTY) + check_channel_property(cf_client, name=DEFAULT_CHANNEL_NAME) + + +class TestRemoveAlias: + def test_remove_alias(self, setup_compose: DockerCompose) -> None: # noqa: F811 + """ + Test that removing an alias works correctly. + """ + # Arrange + docker_ioc = start_ioc(setup_compose) + LOG.info("Waiting for channels to sync") + cf_client = create_client_and_wait(setup_compose, expected_channel_count=BASE_IOC_CHANNEL_COUNT) + + # Check before alias status + LOG.debug('Checking ioc1-1 has ai:base_pv3 has an Active alias"') + channel_alias_name = f"{DEFAULT_CHANNEL_NAME}:alias" + check_channel_property(cf_client, name=DEFAULT_CHANNEL_NAME) + check_channel_property(cf_client, name=channel_alias_name) + + # Act + restart_ioc(docker_ioc, cf_client, DEFAULT_CHANNEL_NAME, "test_remove_alias_after.db") - channel = cf_client.find(name=DEFAULT_CHANNEL_NAME) - LOG.debug("archive channel: %s", channel) - assert get_len_archive_properties(channel) == 0 + # Assert + check_channel_property(cf_client, name=DEFAULT_CHANNEL_NAME) + check_channel_property(cf_client, name=channel_alias_name, prop=INACTIVE_PROPERTY) diff --git a/server/tests/test_multiple_recceiver.py b/server/tests/test_multiple_recceiver.py index c6cbeb5..c360e9c 100644 --- a/server/tests/test_multiple_recceiver.py +++ b/server/tests/test_multiple_recceiver.py @@ -5,15 +5,15 @@ from channelfinder import ChannelFinderClient from testcontainers.compose import DockerCompose -from .client_checks import DEFAULT_CHANNEL_NAME, create_client_and_wait +from .client_checks import BASE_ALIAS_COUNT, BASE_IOC_CHANNEL_COUNT, DEFAULT_CHANNEL_NAME, create_client_and_wait from .docker import ComposeFixtureFactory LOG: logging.Logger = logging.getLogger(__name__) RECSYNC_RESTART_DELAY = 30 # Number of channels expected in the default setup -# 4 iocs, 1 channel 1 alias in archive.db -EXPECTED_DEFAULT_CHANNEL_COUNT = 4 * 2 +IOC_COUNT = 4 +EXPECTED_DEFAULT_CHANNEL_COUNT = IOC_COUNT * BASE_IOC_CHANNEL_COUNT setup_compose = ComposeFixtureFactory(Path("tests") / "docker" / "test-multi-recc.yml").return_fixture() @@ -32,7 +32,7 @@ def test_number_of_channels_and_channel_name(self, cf_client: ChannelFinderClien # Smoke Test Default Properties def test_number_of_aliases_and_alais_property(self, cf_client: ChannelFinderClient) -> None: channels = cf_client.find(property=[("alias", "*")]) - assert len(channels) == 4 + assert len(channels) == IOC_COUNT * BASE_ALIAS_COUNT assert channels[0]["name"] == DEFAULT_CHANNEL_NAME + ":alias" assert { "name": "alias", @@ -43,7 +43,7 @@ def test_number_of_aliases_and_alais_property(self, cf_client: ChannelFinderClie def test_number_of_recordDesc_and_property(self, cf_client: ChannelFinderClient) -> None: channels = cf_client.find(property=[("recordDesc", "*")]) - assert len(channels) == 8 + assert len(channels) == EXPECTED_DEFAULT_CHANNEL_COUNT assert { "name": "recordDesc", "value": "testdesc", diff --git a/server/tests/test_single_ioc.py b/server/tests/test_single_ioc.py index 50a700c..bda1b3b 100644 --- a/server/tests/test_single_ioc.py +++ b/server/tests/test_single_ioc.py @@ -7,6 +7,7 @@ from testcontainers.compose import DockerCompose from .client_checks import ( + BASE_IOC_CHANNEL_COUNT, DEFAULT_CHANNEL_NAME, INACTIVE_PROPERTY, channels_match, @@ -26,14 +27,12 @@ LOG: logging.Logger = logging.getLogger(__name__) -EXPECTED_DEFAULT_CHANNEL_COUNT = 2 - setup_compose = ComposeFixtureFactory(Path("tests") / "docker" / "test-single-ioc.yml").return_fixture() @pytest.fixture(scope="class") def cf_client(setup_compose: DockerCompose) -> ChannelFinderClient: # noqa: F811 - return create_client_and_wait(setup_compose, expected_channel_count=EXPECTED_DEFAULT_CHANNEL_COUNT) + return create_client_and_wait(setup_compose, expected_channel_count=BASE_IOC_CHANNEL_COUNT) class TestRestartIOC: