From a76266d718995a64521483cdb1c957a988158109 Mon Sep 17 00:00:00 2001 From: Kim Hammar Date: Sun, 18 Aug 2024 12:06:41 +0200 Subject: [PATCH] update integration tests --- emulation-system/tests/pytest.ini | 5 + emulation-system/tests/test_all_containers.py | 17 ++- emulation-system/tests/test_container.py | 41 ------- .../tests/test_ping_all_containers.py | 51 +++++---- emulation-system/tests/test_ping_container.py | 102 ------------------ .../tests/test_start_host_manager.py | 47 ++++---- .../src/csle_common/constants/constants.py | 2 +- .../csle_common/metastore/metastore_facade.py | 2 +- type_checker.sh | 2 +- 9 files changed, 81 insertions(+), 188 deletions(-) create mode 100644 emulation-system/tests/pytest.ini delete mode 100644 emulation-system/tests/test_container.py delete mode 100644 emulation-system/tests/test_ping_container.py diff --git a/emulation-system/tests/pytest.ini b/emulation-system/tests/pytest.ini new file mode 100644 index 000000000..6f7af3dab --- /dev/null +++ b/emulation-system/tests/pytest.ini @@ -0,0 +1,5 @@ +[pytest] +log_format = %(asctime)s %(levelname)s %(message)s +log_date_format = %Y-%m-%d %H:%M:%S +log_cli=true +log_level=INFO \ No newline at end of file diff --git a/emulation-system/tests/test_all_containers.py b/emulation-system/tests/test_all_containers.py index c8629bad5..7ab418a6f 100644 --- a/emulation-system/tests/test_all_containers.py +++ b/emulation-system/tests/test_all_containers.py @@ -1,6 +1,9 @@ +from typing import Generator import pytest import docker +import logging import csle_common.constants.constants as constants +from csle_common.metastore.metastore_facade import MetastoreFacade @pytest.fixture(scope="module") @@ -14,26 +17,30 @@ def docker_client() -> None: @pytest.fixture(scope="module") -def containers(docker_client) -> None: +def containers(docker_client) -> Generator: """ Starts Docker containers before running tests and ensures its stopped and removed after tests complete. :param docker_client: docker_client :return: None """ - match_tag = "0.6.0" + config = MetastoreFacade.get_config(id=1) + match_tag = config.version all_images = docker_client.images.list() images = [image for image in all_images - if (any(match_tag in tag for tag in image.tags) and all(constants.CONTAINER_IMAGES.BASE not in tag for tag in image.tags) - and all(f"{constants.CONTAINER_IMAGES.DOCKERHUB_USERNAME}/{constants.CONTAINER_IMAGES.BLANK_UBUNTU_22}:0.6.0" not in tag for tag in image.tags))] + if (any(match_tag in tag for tag in image.tags) + and all(constants.CONTAINER_IMAGES.BASE not in tag for tag in image.tags) + and all(f"{constants.CONTAINER_IMAGES.BLANK}" not in tag for tag in image.tags))] started_containers = [] try: for image in images: + logging.info(f"Starting a container with image {image.tags}") container = docker_client.containers.run(image.id, detach=True) started_containers.append(container) yield started_containers finally: for container in started_containers: + logging.info(f"Stopping and removing container: {container.id} with image {container.image.tags}") container.stop() container.remove() @@ -48,7 +55,9 @@ def test_container_running(docker_client, containers) -> None: running_containers = docker_client.containers.list() failed_containers = [] for container in containers: + logging.info(f"Verifying that container {container.id} with image {container.image.tags} is running") if container not in running_containers: + logging.info(f"Container {container.id} with image {container.image.tags} is not running") failed_containers.append(f"Container with ID {container.id} and image {container.image.tags} is not " f"running.") assert not failed_containers, f"Some containers failed to run: {failed_containers}" diff --git a/emulation-system/tests/test_container.py b/emulation-system/tests/test_container.py deleted file mode 100644 index 7460e7e05..000000000 --- a/emulation-system/tests/test_container.py +++ /dev/null @@ -1,41 +0,0 @@ -import pytest -import docker -import csle_common.constants.constants as constants - - -@pytest.fixture(scope="module") -def docker_client() -> None: - """ - Provide a Docker client instance - - :return: None - """ - return docker.from_env() - - -@pytest.fixture(scope="module") -def container(docker_client) -> None: - """ - Starts a Docker container before running tests and ensures its stopped and removed after tests complete. - - :param docker_client: docker_client - - :return: None - """ - image_with_tag = f"{constants.CONTAINER_IMAGES.DOCKERHUB_USERNAME}/{constants.CONTAINER_IMAGES.FTP_1}:0.6.0" - container = docker_client.containers.run(image_with_tag, detach=True) - yield container - container.stop() - container.remove() - - -def test_container_running(docker_client, container) -> None: - """ - Checks if the container is running and check if its in the running containers list - - :param docker_client: docker_client - - :return: None - """ - running_containers = docker_client.containers.list() - assert container in running_containers diff --git a/emulation-system/tests/test_ping_all_containers.py b/emulation-system/tests/test_ping_all_containers.py index fced9ce05..13a565c00 100644 --- a/emulation-system/tests/test_ping_all_containers.py +++ b/emulation-system/tests/test_ping_all_containers.py @@ -1,7 +1,10 @@ +from typing import Generator import pytest import docker +import logging from docker.types import IPAMConfig, IPAMPool import csle_common.constants.constants as constants +from csle_common.metastore.metastore_facade import MetastoreFacade @pytest.fixture(scope="module") @@ -15,82 +18,87 @@ def docker_client() -> None: @pytest.fixture(scope="module") -def network(docker_client) -> None: +def network(docker_client) -> Generator: """ Create a custom network with a specific subnet :param docker_client: docker_client :yield: network - :return: None """ - # Create a custom network - ipam_pool = IPAMPool(subnet="15.15.15.0/24") + subnet = "15.15.15.0/24" + ipam_pool = IPAMPool(subnet=subnet) ipam_config = IPAMConfig(pool_configs=[ipam_pool]) + logging.info(f"Creating virtual network with subnet: {subnet}") network = docker_client.networks.create("test_network", driver="bridge", ipam=ipam_config) yield network network.remove() @pytest.fixture(scope="module") -def blank1(docker_client, network) -> None: +def blank1(docker_client, network) -> Generator: """ Create and start the first container with a specific IP :param docker_client: docker_client :param network: network :yield: container - :return: None """ - # Create and start the first container with a specific IP + ip = "15.15.15.10" + config = MetastoreFacade.get_config(id=1) + version = config.version container = docker_client.containers.create( - f"{constants.CONTAINER_IMAGES.DOCKERHUB_USERNAME}/{constants.CONTAINER_IMAGES.BLANK_1}:0.6.0", + f"{constants.CONTAINER_IMAGES.DOCKERHUB_USERNAME}/{constants.CONTAINER_IMAGES.BLANK_1}:{version}", command="sh -c 'apt-get update && apt-get install -y iputils-ping && while true; do sleep 3600; done'", detach=True) - network.connect(container, ipv4_address="15.15.15.10") + logging.info(f"Attaching {ip} to container: {container.id} with image: {container.image.tags}") + network.connect(container, ipv4_address=ip) + logging.info(f"Starting container: {container.id} with image: {container.image.tags}") container.start() yield container + logging.info(f"Stopping and removing container: {container.id} with image: {container.image.tags}") container.stop() container.remove() @pytest.fixture(scope="module") -def other_containers(docker_client, network) -> None: +def other_containers(docker_client, network) -> Generator: """ Create and start the second container with a specific IP :param docker_client: docker_client :param network: network :yield: container - :return: None """ - # Create and start the second container with a specific IP - match_tag = "0.6.0" + config = MetastoreFacade.get_config(id=1) + match_tag = config.version all_images = docker_client.images.list() images = [ image for image in all_images - if any(match_tag in tag for tag in image.tags) - and all(constants.CONTAINER_IMAGES.BASE not in tag for tag in image.tags) - and all(f"{constants.CONTAINER_IMAGES.DOCKERHUB_USERNAME}/{constants.CONTAINER_IMAGES.BLANK_UBUNTU_22}:0.6.0" - not in tag for tag in image.tags) - ] + if (any(match_tag in tag for tag in image.tags) + and all(constants.CONTAINER_IMAGES.BASE not in tag for tag in image.tags) + and all(constants.CONTAINER_IMAGES.BLANK not in tag for tag in image.tags))] containers = [] start_ip = 11 for image in images: + ip = f"15.15.15.{start_ip}" container = docker_client.containers.create( image.tags[0], command="sh -c 'apt-get update && apt-get install -y iputils-ping && while true; do sleep 3600; done'", detach=True, ) - network.connect(container, ipv4_address=f"15.15.15.{start_ip}") + logging.info(f"Attaching {ip} to container: {container.id} with image: {container.image.tags}") + network.connect(container, ipv4_address=ip) + logging.info(f"Starting container: {container.id} with image: {container.image.tags}") container.start() containers.append((container, f"15.15.15.{start_ip}")) start_ip += 1 yield containers for container, _ in containers: + logging.info(f"Stopping and removing container: {container.id} with image: {container.image.tags}") container.stop() container.remove() @@ -108,10 +116,12 @@ def test_ping_containers(blank1, other_containers) -> None: assert blank1.status == "running", "Container1 is not running" # Ping container2 from blank1 for container, ip in other_containers: + logging.info(f"Starting container: {container.id} with image: {container.image.tags}") container.start() container.reload() assert container.status == "running", "Container2 is not running" try: + logging.info(f"Pinging ip: {ip} from container {blank1.id} with image: {blank1.image.tags}") exec_result = blank1.exec_run(f"ping -c 3 {ip}") output = exec_result.output.decode("utf-8") # Check if the ping was successful @@ -119,10 +129,11 @@ def test_ping_containers(blank1, other_containers) -> None: if "3 packets transmitted, 3 received" not in output: failed_tests.append(f"Ping to {container.image.tags} from blank1 failed. Logs: {output}") except Exception as e: + logging.info(f"Failed to ping ip: {ip} from container {blank1.id} with image: {blank1.image.tags}") failed_tests.append( f"Ping to {container.image.tags} from blank1 failed. Container: {container.image.tags}, " f"IP: {ip}, Error: {str(e)}") if failed_tests: for fail in failed_tests: - print(fail) + logging.info(fail) assert False, "Some ping tests failed, see the output above for details." diff --git a/emulation-system/tests/test_ping_container.py b/emulation-system/tests/test_ping_container.py deleted file mode 100644 index be3867b56..000000000 --- a/emulation-system/tests/test_ping_container.py +++ /dev/null @@ -1,102 +0,0 @@ -import pytest -import docker -from docker.types import IPAMConfig, IPAMPool -import csle_common.constants.constants as constants - - -@pytest.fixture(scope="module") -def docker_client() -> None: - """ - Initialize and Provide a Docker client instance for the test - - :return: None - """ - return docker.from_env() - - -@pytest.fixture(scope="module") -def network(docker_client) -> None: - """ - Create a custom network with a specific subnet - - :param docker_client: docker_client - :yield: network - - :return: None - """ - # Create a custom network - ipam_pool = IPAMPool(subnet="15.15.15.0/24") - ipam_config = IPAMConfig(pool_configs=[ipam_pool]) - network = docker_client.networks.create("test_network", driver="bridge", ipam=ipam_config) - yield network - network.remove() - - -@pytest.fixture(scope="module") -def container1(docker_client, network) -> None: - """ - Create and start the first container with a specific IP - - :param docker_client: docker_client - :param network: network - :yield: container - - :return: None - """ - # Create and start the first container with a specific IP - container = docker_client.containers.create( - f"{constants.CONTAINER_IMAGES.DOCKERHUB_USERNAME}/{constants.CONTAINER_IMAGES.SPARK_1}:0.6.0", - command="sh -c 'while true; do sleep 3600; done'", - name="test_container1", - detach=True - ) - network.connect(container, ipv4_address="15.15.15.15") - container.start() - yield container - container.stop() - container.remove() - - -@pytest.fixture(scope="module") -def container2(docker_client, network): - """ - Create and start the second container with a specific IP - - :param docker_client: docker_client - :param network: network - :yield: container - - :return: None - """ - # Create and start the second container with a specific IP - container = docker_client.containers.create( - f"{constants.CONTAINER_IMAGES.DOCKERHUB_USERNAME}/{constants.CONTAINER_IMAGES.ELK_1}:0.6.0", - command="sh -c 'while true; do sleep 3600; done'", - name="test_container2", - detach=True - ) - network.connect(container, ipv4_address="15.15.15.14") - container.start() - yield container - container.stop() - container.remove() - - -def test_ping_containers(container1, container2) -> None: - """ - Ping container1 from container2 - - :return: None - """ - container1.start() - container2.start() - container1.reload() - container2.reload() - # Check if containers are running - assert container1.status == 'running', "Container1 is not running" - assert container2.status == 'running', "Container2 is not running" - # Ping container2 from container1 - exec_result = container2.exec_run("ping -c 3 15.15.15.15") - output = exec_result.output.decode('utf-8') - # Check if the ping was successful - assert "3 packets transmitted, 3 received" in output, f"Ping failed. Logs: {output}" diff --git a/emulation-system/tests/test_start_host_manager.py b/emulation-system/tests/test_start_host_manager.py index 20380693c..54a04c4d4 100644 --- a/emulation-system/tests/test_start_host_manager.py +++ b/emulation-system/tests/test_start_host_manager.py @@ -1,5 +1,6 @@ -from typing import List, Any +from typing import List, Any, Generator import pytest +import logging import docker import grpc from unittest.mock import MagicMock @@ -9,6 +10,8 @@ import csle_common.constants.constants as constants import csle_collector.host_manager.host_manager_pb2_grpc import csle_collector.host_manager.host_manager_pb2 +import csle_collector.host_manager.query_host_manager +from csle_common.metastore.metastore_facade import MetastoreFacade @pytest.fixture(scope="module") @@ -22,7 +25,7 @@ def docker_client() -> None: @pytest.fixture(scope="module") -def network(docker_client) -> None: +def network(docker_client) -> Generator: """ Create a custom network with a specific subnet @@ -31,8 +34,10 @@ def network(docker_client) -> None: :return: None """ - ipam_pool = IPAMPool(subnet="15.15.15.0/24") + subnet = "15.15.15.0/24" + ipam_pool = IPAMPool(subnet=subnet) ipam_config = IPAMConfig(pool_configs=[ipam_pool]) + logging.info(f"Creating virtual network with subnet: {subnet}") network = docker_client.networks.create("test_network", driver="bridge", ipam=ipam_config) yield network network.remove() @@ -47,16 +52,18 @@ def get_derived_containers(docker_client, excluded_tag="blank") -> List[Any]: :return: None """ # Get all images except those with the excluded tag - match_tag = "0.6.0" + config = MetastoreFacade.get_config(id=1) + match_tag = config.version all_images = docker_client.images.list() - derived_images = [image for image in all_images if (any(match_tag in tag for tag in image.tags) - and all(constants.CONTAINER_IMAGES.BASE not in tag for tag in image.tags) - and all(excluded_tag not in tag for tag in image.tags))] + derived_images = [image for image in all_images + if (any(match_tag in tag for tag in image.tags) + and all(constants.CONTAINER_IMAGES.BASE not in tag for tag in image.tags) + and all(excluded_tag not in tag for tag in image.tags))] return derived_images @pytest.fixture(scope="module", params=get_derived_containers(docker.from_env())) -def container_setup(request, docker_client, network) -> None: +def container_setup(request, docker_client, network) -> Generator: """ Starts a Docker container before running tests and ensures its stopped and removed after tests complete. @@ -68,14 +75,13 @@ def container_setup(request, docker_client, network) -> None: """ # Create and start each derived container image = request.param - container = docker_client.containers.create( - image.tags[0], # Use the first tag for the image - command="sh -c 'while true; do sleep 3600; done'", - detach=True, - ) + container = docker_client.containers.create(image.tags[0], command="sh -c 'while true; do sleep 3600; done'", + detach=True) network.connect(container) + logging.info(f"Starting container: {container.id} with image: {container.image.tags}") container.start() yield container + logging.info(f"Stopping and removing container: {container.id} with image: {container.image.tags}") container.stop() container.remove() @@ -85,7 +91,6 @@ def test_start_host_manager(container_setup) -> None: Start host_manager in a container :param container_setup: container_setup - :return: None """ failed_containers = [] @@ -112,13 +117,19 @@ def test_start_host_manager(container_setup) -> None: f"--logfile {emulation_env_config.host_manager_config.host_manager_log_file} " f"--maxworkers {emulation_env_config.host_manager_config.host_manager_max_workers}" ) + # Run cmd in the container - result = container_setup.exec_run(cmd, detach=True) + logging.info(f"Starting host manager in container: {container_setup.id} " + f"with image: {container_setup.image.tags}") + container_setup.exec_run(cmd, detach=True) + # Check if host_manager starts cmd = ( f"sh -c '{constants.COMMANDS.PS_AUX} | {constants.COMMANDS.GREP} " f"{constants.COMMANDS.SPACE_DELIM}{constants.TRAFFIC_COMMANDS.HOST_MANAGER_FILE_NAME}'" ) + logging.info(f"Verifying that host manager is running in container: {container_setup.id} " + f"with image: {container_setup.image.tags}") result = container_setup.exec_run(cmd) output = result.output.decode("utf-8") assert constants.COMMANDS.SEARCH_HOST_MANAGER in output, "Host manager is not running in the container" @@ -129,7 +140,7 @@ def test_start_host_manager(container_setup) -> None: status = csle_collector.host_manager.query_host_manager.get_host_status(stub=stub) assert status except Exception as e: - print(f"Error occurred in container {container_setup.name}: {e}") + logging.info(f"Error occurred in container {container_setup.name}: {e}") failed_containers.append(container_setup.name) containers_info.append( { @@ -140,6 +151,6 @@ def test_start_host_manager(container_setup) -> None: } ) if failed_containers: - print("Containers that failed to start the host manager:") - print(containers_info) + logging.info("Containers that failed to start the host manager:") + logging.info(containers_info) assert not failed_containers, f"T{failed_containers} failed" diff --git a/simulation-system/libs/csle-common/src/csle_common/constants/constants.py b/simulation-system/libs/csle-common/src/csle_common/constants/constants.py index 6bb9ae1c5..29f541325 100644 --- a/simulation-system/libs/csle-common/src/csle_common/constants/constants.py +++ b/simulation-system/libs/csle-common/src/csle_common/constants/constants.py @@ -51,7 +51,7 @@ class CONTAINER_IMAGES: BASE = "base" DERIVED = "derived" DOCKERHUB_USERNAME = "kimham" - BLANK_UBUNTU_22 = "csle_blank_ubuntu_22" + BLANK = "csle_blank" BLANK_1 = "csle_blank_1" SSH_1 = "csle_ssh_1" ROUTER_2 = "csle_router_2" diff --git a/simulation-system/libs/csle-common/src/csle_common/metastore/metastore_facade.py b/simulation-system/libs/csle-common/src/csle_common/metastore/metastore_facade.py index 961b60f88..ab4a29ba6 100644 --- a/simulation-system/libs/csle-common/src/csle_common/metastore/metastore_facade.py +++ b/simulation-system/libs/csle-common/src/csle_common/metastore/metastore_facade.py @@ -3885,7 +3885,7 @@ def save_config(config: Config) -> Union[Any, int]: :param config: the config to save :return: id of the config """ - Logger.__call__().get_logger().debug("Saving a config in the metastore") + Logger.__call__().get_logger().info("Updating the configuration in the metastore") with psycopg.connect(f"{constants.METADATA_STORE.DB_NAME_PROPERTY}={constants.METADATA_STORE.DBNAME} " f"{constants.METADATA_STORE.USER_PROPERTY}={constants.METADATA_STORE.USER} " f"{constants.METADATA_STORE.PW_PROPERTY}={constants.METADATA_STORE.PASSWORD} " diff --git a/type_checker.sh b/type_checker.sh index 86c48e95b..23afa455a 100755 --- a/type_checker.sh +++ b/type_checker.sh @@ -33,4 +33,4 @@ cd simulation-system/libs/gym-csle-cyborg; mypy src tests; cd ../../../ echo "Running type checker for csle-attack-profiler" cd simulation-system/libs/csle-attack-profiler; mypy src tests; cd ../../../ echo "Running type checker for emulation-system tests" -cd emulation-system/; mypy tests; cd ../ +cd emulation-system/; mypy tests --ignore-missing-imports; cd ../