From b7b718f25d142a53526876b20fbdeb9abc47ab06 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Fri, 24 Nov 2023 15:15:56 +0000 Subject: [PATCH] #2064: added a method that checks if the class can perform actions and added it where necessary + tests everywhere --- src/primaite/game/agent/observations.py | 2 +- .../system/applications/application.py | 33 +++++- .../system/applications/database_client.py | 23 +++- .../system/applications/web_browser.py | 3 + .../services/database/database_service.py | 8 ++ .../system/services/dns/dns_client.py | 10 +- .../system/services/dns/dns_server.py | 6 + .../simulator/system/services/service.py | 23 +++- src/primaite/simulator/system/software.py | 25 +++- .../system/test_application_on_node.py | 110 ++++++++++++++++++ ...ice_on_node.py => test_service_on_node.py} | 60 +++++++--- .../system/test_web_client_server.py | 22 ++++ .../_simulator/_system/_services/test_dns.py | 41 +++++++ ...sim_conatiner.py => test_sim_container.py} | 0 14 files changed, 328 insertions(+), 38 deletions(-) create mode 100644 tests/integration_tests/system/test_application_on_node.py rename tests/integration_tests/system/{test_app_service_on_node.py => test_service_on_node.py} (64%) rename tests/unit_tests/_primaite/_simulator/{test_sim_conatiner.py => test_sim_container.py} (100%) diff --git a/src/primaite/game/agent/observations.py b/src/primaite/game/agent/observations.py index a74771c0..dcb03d00 100644 --- a/src/primaite/game/agent/observations.py +++ b/src/primaite/game/agent/observations.py @@ -263,7 +263,7 @@ class FolderObservation(AbstractObservation): self.files.append(FileObservation()) while len(self.files) > num_files_per_folder: truncated_file = self.files.pop() - msg = f"Too many files in folde observation. Truncating file {truncated_file}" + msg = f"Too many files in folder observation. Truncating file {truncated_file}" _LOGGER.warn(msg) self.default_observation = { diff --git a/src/primaite/simulator/system/applications/application.py b/src/primaite/simulator/system/applications/application.py index fb65354f..d2f9772d 100644 --- a/src/primaite/simulator/system/applications/application.py +++ b/src/primaite/simulator/system/applications/application.py @@ -2,9 +2,11 @@ from abc import abstractmethod from enum import Enum from typing import Any, Dict, Set -from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState +from primaite import getLogger from primaite.simulator.system.software import IOSoftware, SoftwareHealthState +_LOGGER = getLogger(__name__) + class ApplicationOperatingState(Enum): """Enumeration of Application Operating States.""" @@ -52,7 +54,7 @@ class Application(IOSoftware): state = super().describe_state() state.update( { - "opearting_state": self.operating_state.value, + "operating_state": self.operating_state.value, "execution_control_status": self.execution_control_status, "num_executions": self.num_executions, "groups": list(self.groups), @@ -60,10 +62,28 @@ class Application(IOSoftware): ) return state + def _can_perform_action(self) -> bool: + """ + Checks if the application can perform actions. + + This is done by checking if the application is operating properly or the node it is installed + in is operational. + + Returns true if the software can perform actions. + """ + if not super()._can_perform_action(): + return False + + if self.operating_state is not self.operating_state.RUNNING: + # service is not running + _LOGGER.error(f"Cannot perform action: {self.name} is {self.operating_state.name}") + return False + + return True + def run(self) -> None: """Open the Application.""" - if self.software_manager and self.software_manager.node.operating_state is not NodeOperatingState.ON: - self.sys_log.error(f"Unable to run application. {self.software_manager.node.hostname} is not turned on.") + if not super()._can_perform_action(): return if self.operating_state == ApplicationOperatingState.CLOSED: @@ -78,6 +98,9 @@ class Application(IOSoftware): def install(self) -> None: """Install Application.""" + if self._can_perform_action(): + return + super().install() if self.operating_state == ApplicationOperatingState.CLOSED: self.sys_log.info(f"Installing Application {self.name}") @@ -102,4 +125,4 @@ class Application(IOSoftware): :param payload: The payload to receive. :return: True if successful, False otherwise. """ - pass + return super().receive(payload=payload, session_id=session_id, **kwargs) diff --git a/src/primaite/simulator/system/applications/database_client.py b/src/primaite/simulator/system/applications/database_client.py index 37f89371..9cb87bf6 100644 --- a/src/primaite/simulator/system/applications/database_client.py +++ b/src/primaite/simulator/system/applications/database_client.py @@ -54,7 +54,10 @@ class DatabaseClient(Application): def connect(self) -> bool: """Connect to a Database Service.""" - if not self.connected and self.operating_state.RUNNING: + if not self._can_perform_action(): + return False + + if not self.connected: return self._connect(self.server_ip_address, self.server_password) return False @@ -135,19 +138,31 @@ class DatabaseClient(Application): self.operating_state = ApplicationOperatingState.RUNNING self.connect() - def query(self, sql: str) -> bool: + def query(self, sql: str, is_reattempt: bool = False) -> bool: """ Send a query to the Database Service. - :param sql: The SQL query. + :param: sql: The SQL query. + :param: is_reattempt: If true, the action has been reattempted. :return: True if the query was successful, otherwise False. """ - if self.connected and self.operating_state.RUNNING: + if not self._can_perform_action(): + return False + + if self.connected: query_id = str(uuid4()) # Initialise the tracker of this ID to False self._query_success_tracker[query_id] = False return self._query(sql=sql, query_id=query_id) + else: + if is_reattempt: + return False + + if not self.connect(): + return False + + self.query(sql=sql, is_reattempt=True) def receive(self, payload: Any, session_id: str, **kwargs) -> bool: """ diff --git a/src/primaite/simulator/system/applications/web_browser.py b/src/primaite/simulator/system/applications/web_browser.py index bb9552d8..71e30c7f 100644 --- a/src/primaite/simulator/system/applications/web_browser.py +++ b/src/primaite/simulator/system/applications/web_browser.py @@ -65,6 +65,9 @@ class WebBrowser(Application): :param: url: The address of the web page the browser requests :type: url: str """ + if not self._can_perform_action(): + return False + # reset latest response self.latest_response = HttpResponsePacket(status_code=HttpStatusCode.NOT_FOUND) diff --git a/src/primaite/simulator/system/services/database/database_service.py b/src/primaite/simulator/system/services/database/database_service.py index e3adb8e1..740ed4fd 100644 --- a/src/primaite/simulator/system/services/database/database_service.py +++ b/src/primaite/simulator/system/services/database/database_service.py @@ -48,6 +48,10 @@ class DatabaseService(Service): def backup_database(self) -> bool: """Create a backup of the database to the configured backup server.""" + # check if this action can be performed + if not self._can_perform_action(): + return False + # check if the backup server was configured if self.backup_server is None: self.sys_log.error(f"{self.name} - {self.sys_log.hostname}: not configured.") @@ -73,6 +77,10 @@ class DatabaseService(Service): def restore_backup(self) -> bool: """Restore a backup from backup server.""" + # check if this action can be performed + if not self._can_perform_action(): + return False + software_manager: SoftwareManager = self.software_manager ftp_client_service: FTPClient = software_manager.software["FTPClient"] diff --git a/src/primaite/simulator/system/services/dns/dns_client.py b/src/primaite/simulator/system/services/dns/dns_client.py index 266ac4f6..a0965009 100644 --- a/src/primaite/simulator/system/services/dns/dns_client.py +++ b/src/primaite/simulator/system/services/dns/dns_client.py @@ -1,5 +1,5 @@ from ipaddress import IPv4Address -from typing import Dict, Optional +from typing import Dict, Optional, Union from primaite import getLogger from primaite.simulator.network.protocols.dns import DNSPacket, DNSRequest @@ -51,13 +51,16 @@ class DNSClient(Service): """ pass - def add_domain_to_cache(self, domain_name: str, ip_address: IPv4Address): + def add_domain_to_cache(self, domain_name: str, ip_address: IPv4Address) -> Union[bool, None]: """ Adds a domain name to the DNS Client cache. :param: domain_name: The domain name to save to cache :param: ip_address: The IP Address to attach the domain name to """ + if not self._can_perform_action(): + return False + self.dns_cache[domain_name] = ip_address def check_domain_exists( @@ -72,6 +75,9 @@ class DNSClient(Service): :param: session_id: The Session ID the payload is to originate from. Optional. :param: is_reattempt: Checks if the request has been reattempted. Default is False. """ + if not self._can_perform_action(): + return False + # check if DNS server is configured if self.dns_server is None: self.sys_log.error(f"{self.name}: DNS Server is not configured") diff --git a/src/primaite/simulator/system/services/dns/dns_server.py b/src/primaite/simulator/system/services/dns/dns_server.py index 2c8f3003..b6d4961f 100644 --- a/src/primaite/simulator/system/services/dns/dns_server.py +++ b/src/primaite/simulator/system/services/dns/dns_server.py @@ -48,6 +48,9 @@ class DNSServer(Service): :param target_domain: The single domain name requested by a DNS client. :return ip_address: The IP address of that domain name or None. """ + if not self._can_perform_action(): + return + return self.dns_table.get(target_domain) def dns_register(self, domain_name: str, domain_ip_address: IPv4Address): @@ -60,6 +63,9 @@ class DNSServer(Service): :param: domain_ip_address: The IP address that the domain should route to :type: domain_ip_address: IPv4Address """ + if not self._can_perform_action(): + return + self.dns_table[domain_name] = domain_ip_address def reset_component_for_episode(self, episode: int): diff --git a/src/primaite/simulator/system/services/service.py b/src/primaite/simulator/system/services/service.py index 3a1a4c9d..04a4603a 100644 --- a/src/primaite/simulator/system/services/service.py +++ b/src/primaite/simulator/system/services/service.py @@ -3,7 +3,6 @@ from typing import Any, Dict, Optional from primaite import getLogger from primaite.simulator.core import RequestManager, RequestType -from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState from primaite.simulator.system.software import IOSoftware, SoftwareHealthState _LOGGER = getLogger(__name__) @@ -41,6 +40,25 @@ class Service(IOSoftware): restart_countdown: Optional[int] = None "If currently restarting, how many timesteps remain until the restart is finished." + def _can_perform_action(self) -> bool: + """ + Checks if the service can perform actions. + + This is done by checking if the service is operating properly or the node it is installed + in is operational. + + Returns true if the software can perform actions. + """ + if not super()._can_perform_action(): + return False + + if self.operating_state is not self.operating_state.RUNNING: + # service is not running + _LOGGER.error(f"Cannot perform action: {self.name} is {self.operating_state.name}") + return False + + return True + def receive(self, payload: Any, session_id: str, **kwargs) -> bool: """ Receives a payload from the SessionManager. @@ -108,8 +126,7 @@ class Service(IOSoftware): def start(self, **kwargs) -> None: """Start the service.""" # cant start the service if the node it is on is off - if self.software_manager and self.software_manager.node.operating_state is not NodeOperatingState.ON: - self.sys_log.error(f"Unable to start service. {self.software_manager.node.hostname} is not turned on.") + if not super()._can_perform_action(): return if self.operating_state == ServiceOperatingState.STOPPED: diff --git a/src/primaite/simulator/system/software.py b/src/primaite/simulator/system/software.py index 830e3d79..5564bd48 100644 --- a/src/primaite/simulator/system/software.py +++ b/src/primaite/simulator/system/software.py @@ -226,6 +226,21 @@ class IOSoftware(Software): ) return state + @abstractmethod + def _can_perform_action(self) -> bool: + """ + Checks if the software can perform actions. + + This is done by checking if the software is operating properly or the node it is installed + in is operational. + + Returns true if the software can perform actions. + """ + if self.software_manager and self.software_manager.node.operating_state is NodeOperatingState.OFF: + _LOGGER.debug(f"{self.name} Error: {self.software_manager.node.hostname} is not online.") + return False + return True + def send( self, payload: Any, @@ -244,6 +259,9 @@ class IOSoftware(Software): :return: True if successful, False otherwise. """ + if not self._can_perform_action(): + return False + return self.software_manager.send_payload_to_session_manager( payload=payload, dest_ip_address=dest_ip_address, dest_port=dest_port, session_id=session_id ) @@ -262,8 +280,5 @@ class IOSoftware(Software): :param kwargs: Additional keyword arguments specific to the implementation. :return: True if the payload was successfully received and processed, False otherwise. """ - # return false if node that software is on is off - if self.software_manager and self.software_manager.node.operating_state is NodeOperatingState.OFF: - _LOGGER.debug(f"{self.name} Error: {self.software_manager.node.hostname} is not online.") - return False - return True + # return false if not allowed to perform actions + return self._can_perform_action() diff --git a/tests/integration_tests/system/test_application_on_node.py b/tests/integration_tests/system/test_application_on_node.py new file mode 100644 index 00000000..7ac7b492 --- /dev/null +++ b/tests/integration_tests/system/test_application_on_node.py @@ -0,0 +1,110 @@ +from typing import Tuple + +import pytest + +from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState +from primaite.simulator.network.hardware.nodes.computer import Computer +from primaite.simulator.system.applications.application import Application, ApplicationOperatingState + + +@pytest.fixture(scope="function") +def populated_node(application_class) -> Tuple[Application, Computer]: + computer: Computer = Computer( + hostname="test_computer", + ip_address="192.168.1.2", + subnet_mask="255.255.255.0", + default_gateway="192.168.1.1", + operating_state=NodeOperatingState.ON, + ) + computer.software_manager.install(application_class) + + app = computer.software_manager.software["TestApplication"] + app.run() + + return app, computer + + +def test_service_on_offline_node(application_class): + """Test to check that the service cannot be interacted with when node it is on is off.""" + computer: Computer = Computer( + hostname="test_computer", + ip_address="192.168.1.2", + subnet_mask="255.255.255.0", + default_gateway="192.168.1.1", + operating_state=NodeOperatingState.ON, + ) + computer.software_manager.install(application_class) + + app: Application = computer.software_manager.software["TestApplication"] + + computer.power_off() + + for i in range(computer.shut_down_duration + 1): + computer.apply_timestep(timestep=i) + + assert computer.operating_state is NodeOperatingState.OFF + assert app.operating_state is ApplicationOperatingState.CLOSED + + app.run() + assert app.operating_state is ApplicationOperatingState.CLOSED + + +def test_server_turns_off_service(populated_node): + """Check that the service is turned off when the server is turned off""" + app, computer = populated_node + + assert computer.operating_state is NodeOperatingState.ON + assert app.operating_state is ApplicationOperatingState.RUNNING + + computer.power_off() + + for i in range(computer.shut_down_duration + 1): + computer.apply_timestep(timestep=i) + + assert computer.operating_state is NodeOperatingState.OFF + assert app.operating_state is ApplicationOperatingState.CLOSED + + +def test_service_cannot_be_turned_on_when_server_is_off(populated_node): + """Check that the service cannot be started when the server is off.""" + app, computer = populated_node + + assert computer.operating_state is NodeOperatingState.ON + assert app.operating_state is ApplicationOperatingState.RUNNING + + computer.power_off() + + for i in range(computer.shut_down_duration + 1): + computer.apply_timestep(timestep=i) + + assert computer.operating_state is NodeOperatingState.OFF + assert app.operating_state is ApplicationOperatingState.CLOSED + + app.run() + + assert computer.operating_state is NodeOperatingState.OFF + assert app.operating_state is ApplicationOperatingState.CLOSED + + +def test_server_turns_on_service(populated_node): + """Check that turning on the server turns on service.""" + app, computer = populated_node + + assert computer.operating_state is NodeOperatingState.ON + assert app.operating_state is ApplicationOperatingState.RUNNING + + computer.power_off() + + for i in range(computer.shut_down_duration + 1): + computer.apply_timestep(timestep=i) + + assert computer.operating_state is NodeOperatingState.OFF + assert app.operating_state is ApplicationOperatingState.CLOSED + + computer.power_on() + + for i in range(computer.start_up_duration + 1): + computer.apply_timestep(timestep=i) + + assert computer.operating_state is NodeOperatingState.ON + assert app.operating_state is ApplicationOperatingState.RUNNING diff --git a/tests/integration_tests/system/test_app_service_on_node.py b/tests/integration_tests/system/test_service_on_node.py similarity index 64% rename from tests/integration_tests/system/test_app_service_on_node.py rename to tests/integration_tests/system/test_service_on_node.py index 7777a810..b23df58b 100644 --- a/tests/integration_tests/system/test_app_service_on_node.py +++ b/tests/integration_tests/system/test_service_on_node.py @@ -3,34 +3,66 @@ from typing import Tuple import pytest from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState +from primaite.simulator.network.hardware.nodes.computer import Computer from primaite.simulator.network.hardware.nodes.server import Server -from primaite.simulator.system.applications.application import Application, ApplicationOperatingState from primaite.simulator.system.services.service import Service, ServiceOperatingState @pytest.fixture(scope="function") -def populated_node(service_class, application_class) -> Tuple[Application, Server, Service]: +def populated_node( + service_class, +) -> Tuple[Server, Service]: server = Server( hostname="server", ip_address="192.168.0.1", subnet_mask="255.255.255.0", operating_state=NodeOperatingState.ON ) server.software_manager.install(service_class) - server.software_manager.install(application_class) - app = server.software_manager.software["TestApplication"] - app.run() service = server.software_manager.software["TestService"] service.start() - return app, server, service + return server, service + + +def test_service_on_offline_node(service_class): + """Test to check that the service cannot be interacted with when node it is on is off.""" + computer: Computer = Computer( + hostname="test_computer", + ip_address="192.168.1.2", + subnet_mask="255.255.255.0", + default_gateway="192.168.1.1", + operating_state=NodeOperatingState.ON, + ) + computer.software_manager.install(service_class) + + service: Service = computer.software_manager.software["TestService"] + + computer.power_off() + + for i in range(computer.shut_down_duration + 1): + computer.apply_timestep(timestep=i) + + assert computer.operating_state is NodeOperatingState.OFF + assert service.operating_state is ServiceOperatingState.STOPPED + + service.start() + assert service.operating_state is ServiceOperatingState.STOPPED + + service.resume() + assert service.operating_state is ServiceOperatingState.STOPPED + + service.restart() + assert service.operating_state is ServiceOperatingState.STOPPED + + service.pause() + assert service.operating_state is ServiceOperatingState.STOPPED def test_server_turns_off_service(populated_node): """Check that the service is turned off when the server is turned off""" - app, server, service = populated_node + server, service = populated_node assert server.operating_state is NodeOperatingState.ON assert service.operating_state is ServiceOperatingState.RUNNING - assert app.operating_state is ApplicationOperatingState.RUNNING server.power_off() @@ -39,16 +71,14 @@ def test_server_turns_off_service(populated_node): assert server.operating_state is NodeOperatingState.OFF assert service.operating_state is ServiceOperatingState.STOPPED - assert app.operating_state is ApplicationOperatingState.CLOSED def test_service_cannot_be_turned_on_when_server_is_off(populated_node): """Check that the service cannot be started when the server is off.""" - app, server, service = populated_node + server, service = populated_node assert server.operating_state is NodeOperatingState.ON assert service.operating_state is ServiceOperatingState.RUNNING - assert app.operating_state is ApplicationOperatingState.RUNNING server.power_off() @@ -57,23 +87,19 @@ def test_service_cannot_be_turned_on_when_server_is_off(populated_node): assert server.operating_state is NodeOperatingState.OFF assert service.operating_state is ServiceOperatingState.STOPPED - assert app.operating_state is ApplicationOperatingState.CLOSED service.start() - app.run() assert server.operating_state is NodeOperatingState.OFF assert service.operating_state is ServiceOperatingState.STOPPED - assert app.operating_state is ApplicationOperatingState.CLOSED def test_server_turns_on_service(populated_node): """Check that turning on the server turns on service.""" - app, server, service = populated_node + server, service = populated_node assert server.operating_state is NodeOperatingState.ON assert service.operating_state is ServiceOperatingState.RUNNING - assert app.operating_state is ApplicationOperatingState.RUNNING server.power_off() @@ -82,7 +108,6 @@ def test_server_turns_on_service(populated_node): assert server.operating_state is NodeOperatingState.OFF assert service.operating_state is ServiceOperatingState.STOPPED - assert app.operating_state is ApplicationOperatingState.CLOSED server.power_on() @@ -91,4 +116,3 @@ def test_server_turns_on_service(populated_node): assert server.operating_state is NodeOperatingState.ON assert service.operating_state is ServiceOperatingState.RUNNING - assert app.operating_state is ApplicationOperatingState.RUNNING diff --git a/tests/integration_tests/system/test_web_client_server.py b/tests/integration_tests/system/test_web_client_server.py index f3995c84..8f87ef27 100644 --- a/tests/integration_tests/system/test_web_client_server.py +++ b/tests/integration_tests/system/test_web_client_server.py @@ -78,3 +78,25 @@ def test_web_page_request_from_shut_down_server(uc2_network): assert web_client.get_webpage("http://arcd.com/users/") is False assert web_client.latest_response.status_code == HttpStatusCode.NOT_FOUND + + +def test_web_page_request_from_closed_web_browser(uc2_network): + client_1: Computer = uc2_network.get_node_by_hostname("client_1") + web_client: WebBrowser = client_1.software_manager.software["WebBrowser"] + web_client.run() + + web_server: Server = uc2_network.get_node_by_hostname("web_server") + + assert web_client.operating_state == ApplicationOperatingState.RUNNING + + assert web_client.get_webpage("http://arcd.com/users/") is True + + # latest response should have status code 200 + assert web_client.latest_response.status_code == HttpStatusCode.OK + + web_client.close() + + # node should be off + assert web_client.operating_state is ApplicationOperatingState.CLOSED + + assert web_client.get_webpage("http://arcd.com/users/") is False diff --git a/tests/unit_tests/_primaite/_simulator/_system/_services/test_dns.py b/tests/unit_tests/_primaite/_simulator/_system/_services/test_dns.py index 469c8548..2b4082d9 100644 --- a/tests/unit_tests/_primaite/_simulator/_system/_services/test_dns.py +++ b/tests/unit_tests/_primaite/_simulator/_system/_services/test_dns.py @@ -11,6 +11,7 @@ from primaite.simulator.network.transmission.network_layer import IPProtocol from primaite.simulator.network.transmission.transport_layer import Port from primaite.simulator.system.services.dns.dns_client import DNSClient from primaite.simulator.system.services.dns.dns_server import DNSServer +from primaite.simulator.system.services.service import ServiceOperatingState @pytest.fixture(scope="function") @@ -54,6 +55,44 @@ def test_create_dns_client(dns_client): assert dns_client_service.protocol is IPProtocol.TCP +def test_dns_client_add_domain_to_cache_when_not_running(dns_client): + dns_client_service: DNSClient = dns_client.software_manager.software["DNSClient"] + assert dns_client.operating_state is NodeOperatingState.OFF + assert dns_client_service.operating_state is ServiceOperatingState.STOPPED + + assert ( + dns_client_service.add_domain_to_cache(domain_name="test.com", ip_address=IPv4Address("192.168.1.100")) is False + ) + + assert dns_client_service.dns_cache.get("test.com") is None + + +def test_dns_client_check_domain_exists_when_not_running(dns_client): + dns_client.operating_state = NodeOperatingState.ON + dns_client_service: DNSClient = dns_client.software_manager.software["DNSClient"] + dns_client_service.start() + + assert dns_client.operating_state is NodeOperatingState.ON + assert dns_client_service.operating_state is ServiceOperatingState.RUNNING + + assert ( + dns_client_service.add_domain_to_cache(domain_name="test.com", ip_address=IPv4Address("192.168.1.100")) + is not False + ) + + assert dns_client_service.check_domain_exists("test.com") is True + + dns_client.power_off() + + for i in range(dns_client.shut_down_duration + 1): + dns_client.apply_timestep(timestep=i) + + assert dns_client.operating_state is NodeOperatingState.OFF + assert dns_client_service.operating_state is ServiceOperatingState.STOPPED + + assert dns_client_service.check_domain_exists("test.com") is False + + def test_dns_server_domain_name_registration(dns_server): """Test to check if the domain name registration works.""" dns_server_service: DNSServer = dns_server.software_manager.software["DNSServer"] @@ -68,7 +107,9 @@ def test_dns_server_domain_name_registration(dns_server): def test_dns_client_check_domain_in_cache(dns_client): """Test to make sure that the check_domain_in_cache returns the correct values.""" + dns_client.operating_state = NodeOperatingState.ON dns_client_service: DNSClient = dns_client.software_manager.software["DNSClient"] + dns_client_service.start() # add a domain to the dns client cache dns_client_service.add_domain_to_cache("real-domain.com", IPv4Address("192.168.1.12")) diff --git a/tests/unit_tests/_primaite/_simulator/test_sim_conatiner.py b/tests/unit_tests/_primaite/_simulator/test_sim_container.py similarity index 100% rename from tests/unit_tests/_primaite/_simulator/test_sim_conatiner.py rename to tests/unit_tests/_primaite/_simulator/test_sim_container.py