diff --git a/src/primaite/simulator/file_system/file_system.py b/src/primaite/simulator/file_system/file_system.py index bcb0334e..ba72e1ac 100644 --- a/src/primaite/simulator/file_system/file_system.py +++ b/src/primaite/simulator/file_system/file_system.py @@ -653,7 +653,7 @@ class FileSystem(SimComponent): @property def fail_message(self) -> str: """Message that is reported when a request is rejected by this validator.""" - return "Cannot perform request on folder because it does not exist" + return "Cannot perform request on folder because it does not exist." class _FolderNotDeletedValidator(RequestPermissionValidator): """ @@ -693,4 +693,4 @@ class FileSystem(SimComponent): @property def fail_message(self) -> str: """Message that is reported when a request is rejected by this validator.""" - return "Cannot perform request on file that does not exist." + return "Cannot perform request on a file that does not exist." diff --git a/src/primaite/simulator/file_system/folder.py b/src/primaite/simulator/file_system/folder.py index d891641e..c98e4492 100644 --- a/src/primaite/simulator/file_system/folder.py +++ b/src/primaite/simulator/file_system/folder.py @@ -56,6 +56,7 @@ class Folder(FileSystemItemABC): More information in user guide and docstring for SimComponent._init_request_manager. """ self._file_exists = Folder._FileExistsValidator(folder=self) + self._file_not_deleted = Folder._FileNotDeletedValidator(folder=self) rm = super()._init_request_manager() rm.add_request( @@ -67,7 +68,9 @@ class Folder(FileSystemItemABC): self._file_request_manager = RequestManager() rm.add_request( name="file", - request_type=RequestType(func=self._file_request_manager, validator=self._file_exists), + request_type=RequestType( + func=self._file_request_manager, validator=self._file_exists + self._file_not_deleted + ), ) return rm @@ -489,4 +492,24 @@ class Folder(FileSystemItemABC): @property def fail_message(self) -> str: """Message that is reported when a request is rejected by this validator.""" - return "Cannot perform request on file that does not exist." + return "Cannot perform request on a file that does not exist." + + class _FileNotDeletedValidator(RequestPermissionValidator): + """ + When requests come in, this validator will only let them through if the File is not deleted. + + Actions cannot be performed on a deleted file. + """ + + folder: Folder + """Save a reference to the Folder instance.""" + + def __call__(self, request: RequestFormat, context: Dict) -> bool: + """Returns True if file exists and is not deleted.""" + file = self.folder.get_file(file_name=request[0]) + return file is not None and not file.deleted + + @property + def fail_message(self) -> str: + """Message that is reported when a request is rejected by this validator.""" + return "Cannot perform request on a file that is deleted." diff --git a/tests/integration_tests/game_layer/observations/test_nic_observations.py b/tests/integration_tests/game_layer/observations/test_nic_observations.py index f1a8ea92..88dd2bd5 100644 --- a/tests/integration_tests/game_layer/observations/test_nic_observations.py +++ b/tests/integration_tests/game_layer/observations/test_nic_observations.py @@ -155,7 +155,7 @@ def test_nic_monitored_traffic(simulation): assert traffic_obs["icmp"]["outbound"] == 0 # send a ping - pc.ping(target_ip_address=pc2.network_interface[1].ip_address) + assert pc.ping(target_ip_address=pc2.network_interface[1].ip_address) traffic_obs = nic_obs.observe(simulation.describe_state()).get("TRAFFIC") assert traffic_obs["icmp"]["inbound"] == 1 @@ -178,7 +178,7 @@ def test_nic_monitored_traffic(simulation): traffic_obs = nic_obs.observe(simulation.describe_state()).get("TRAFFIC") assert traffic_obs["icmp"]["inbound"] == 0 assert traffic_obs["icmp"]["outbound"] == 0 - assert traffic_obs["tcp"][53]["inbound"] == 0 + assert traffic_obs["tcp"][53]["inbound"] == 1 assert traffic_obs["tcp"][53]["outbound"] == 1 # getting a webpage sent a dns request out simulation.pre_timestep(2) # apply timestep to whole sim diff --git a/tests/unit_tests/_primaite/_simulator/_file_system/test_file_system_actions.py b/tests/unit_tests/_primaite/_simulator/_file_system/test_file_system_actions.py index 209668c4..7d022ea4 100644 --- a/tests/unit_tests/_primaite/_simulator/_file_system/test_file_system_actions.py +++ b/tests/unit_tests/_primaite/_simulator/_file_system/test_file_system_actions.py @@ -39,3 +39,39 @@ def test_folder_delete_request(populated_file_system): assert fs.get_file_by_id(folder_uuid=folder.uuid, file_uuid=file.uuid) is None fs.show(full=True) + + +def test_folder_exists_request_validator(populated_file_system): + """Tests that the _FolderExistsValidator works as intended.""" + fs, folder, file = populated_file_system + validator = FileSystem._FolderExistsValidator(file_system=fs) + + assert validator(request=["test_folder"], context={}) # test_folder exists + assert validator(request=["fake_folder"], context={}) is False # fake_folder does not exist + + assert validator.fail_message == "Cannot perform request on folder because it does not exist." + + +def test_file_exists_request_validator(populated_file_system): + """Tests that the _FolderExistsValidator works as intended.""" + fs, folder, file = populated_file_system + validator = FileSystem._FileExistsValidator(file_system=fs) + + assert validator(request=["test_folder", "test_file.txt"], context={}) # test_file.txt exists + assert validator(request=["test_folder", "fake_file.txt"], context={}) is False # fake_file.txt does not exist + + assert validator.fail_message == "Cannot perform request on a file that does not exist." + + +def test_folder_not_deleted_request_validator(populated_file_system): + """Tests that the _FolderExistsValidator works as intended.""" + fs, folder, file = populated_file_system + validator = FileSystem._FolderNotDeletedValidator(file_system=fs) + + assert validator(request=["test_folder"], context={}) # test_folder is not deleted + + fs.delete_folder(folder_name="test_folder") + + assert validator(request=["test_folder"], context={}) is False # test_folder is deleted + + assert validator.fail_message == "Cannot perform request on folder because it is deleted." diff --git a/tests/unit_tests/_primaite/_simulator/_file_system/test_folder_actions.py b/tests/unit_tests/_primaite/_simulator/_file_system/test_folder_actions.py index 00148311..4a561b97 100644 --- a/tests/unit_tests/_primaite/_simulator/_file_system/test_folder_actions.py +++ b/tests/unit_tests/_primaite/_simulator/_file_system/test_folder_actions.py @@ -178,3 +178,28 @@ def test_deleted_folder_and_its_files_cannot_be_interacted_with(populated_file_s deleted_file = deleted_folder.deleted_files.get(file.uuid) assert deleted_file.health_status is not FileSystemItemHealthStatus.GOOD + + +def test_file_exists_request_validator(populated_file_system): + """Tests that the _FolderExistsValidator works as intended.""" + fs, folder, file = populated_file_system + validator = Folder._FileExistsValidator(folder=folder) + + assert validator(request=["test_file.txt"], context={}) # test_file.txt exists + assert validator(request=["fake_file.txt"], context={}) is False # fake_file.txt does not exist + + assert validator.fail_message == "Cannot perform request on a file that does not exist." + + +def test_file_not_deleted_request_validator(populated_file_system): + """Tests that the _FolderExistsValidator works as intended.""" + fs, folder, file = populated_file_system + validator = Folder._FileNotDeletedValidator(folder=folder) + + assert validator(request=["test_file.txt"], context={}) # test_file.txt is not deleted + + fs.delete_file(folder_name="test_folder", file_name="test_file.txt") + + assert validator(request=["fake_file.txt"], context={}) is False # test_file.txt is deleted + + assert validator.fail_message == "Cannot perform request on a file that is deleted." diff --git a/tests/unit_tests/_primaite/_simulator/_network/_hardware/test_network_interface_actions.py b/tests/unit_tests/_primaite/_simulator/_network/_hardware/test_network_interface_actions.py new file mode 100644 index 00000000..f35cf171 --- /dev/null +++ b/tests/unit_tests/_primaite/_simulator/_network/_hardware/test_network_interface_actions.py @@ -0,0 +1,34 @@ +# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK +import pytest + +from primaite.simulator.network.hardware.base import NetworkInterface, Node +from primaite.simulator.network.hardware.nodes.host.computer import Computer + + +@pytest.fixture +def node() -> Node: + return Computer(hostname="test", ip_address="192.168.1.2", subnet_mask="255.255.255.0") + + +def test_nic_enabled_validator(node): + """Test the NetworkInterface enabled validator.""" + network_interface = node.network_interface[1] + validator = NetworkInterface._EnabledValidator(network_interface=network_interface) + + assert validator(request=[], context={}) is False # not enabled + + network_interface.enabled = True + + assert validator(request=[], context={}) # enabled + + +def test_nic_disabled_validator(node): + """Test the NetworkInterface enabled validator.""" + network_interface = node.network_interface[1] + validator = NetworkInterface._DisabledValidator(network_interface=network_interface) + + assert validator(request=[], context={}) # not enabled + + network_interface.enabled = True + + assert validator(request=[], context={}) is False # enabled diff --git a/tests/unit_tests/_primaite/_simulator/_network/_hardware/test_node_actions.py b/tests/unit_tests/_primaite/_simulator/_network/_hardware/test_node_actions.py index 57d6cecb..9b37ac80 100644 --- a/tests/unit_tests/_primaite/_simulator/_network/_hardware/test_node_actions.py +++ b/tests/unit_tests/_primaite/_simulator/_network/_hardware/test_node_actions.py @@ -155,3 +155,39 @@ def test_reset_node(node): assert node.operating_state == NodeOperatingState.BOOTING assert node.operating_state == NodeOperatingState.ON + + +def test_node_is_on_validator(node): + """Test that the node is on validator.""" + node.power_on() + + for i in range(node.start_up_duration + 1): + node.apply_timestep(i) + + validator = Node._NodeIsOnValidator(node=node) + + assert validator(request=[], context={}) + + node.power_off() + for i in range(node.shut_down_duration + 1): + node.apply_timestep(i) + + assert validator(request=[], context={}) is False + + +def test_node_is_off_validator(node): + """Test that the node is on validator.""" + node.power_on() + + for i in range(node.start_up_duration + 1): + node.apply_timestep(i) + + validator = Node._NodeIsOffValidator(node=node) + + assert validator(request=[], context={}) is False + + node.power_off() + for i in range(node.shut_down_duration + 1): + node.apply_timestep(i) + + assert validator(request=[], context={}) diff --git a/tests/unit_tests/_primaite/_simulator/_system/_applications/test_application_actions.py b/tests/unit_tests/_primaite/_simulator/_system/_applications/test_application_actions.py index be6c00e7..0e9c536c 100644 --- a/tests/unit_tests/_primaite/_simulator/_system/_applications/test_application_actions.py +++ b/tests/unit_tests/_primaite/_simulator/_system/_applications/test_application_actions.py @@ -1 +1,15 @@ # © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK +from primaite.simulator.system.applications.application import Application, ApplicationOperatingState + + +def test_application_state_validator(application): + """Test the application state validator.""" + validator = Application._StateValidator(application=application, state=ApplicationOperatingState.CLOSED) + assert validator(request=[], context={}) # application is closed + application.run() + assert validator(request=[], context={}) is False # application is running - expecting closed + + validator = Application._StateValidator(application=application, state=ApplicationOperatingState.RUNNING) + assert validator(request=[], context={}) # application is running + application.close() + assert validator(request=[], context={}) is False # application is closed - expecting running diff --git a/tests/unit_tests/_primaite/_simulator/_system/_services/test_service_actions.py b/tests/unit_tests/_primaite/_simulator/_system/_services/test_service_actions.py index 2d9a6c52..537beb8b 100644 --- a/tests/unit_tests/_primaite/_simulator/_system/_services/test_service_actions.py +++ b/tests/unit_tests/_primaite/_simulator/_system/_services/test_service_actions.py @@ -1,5 +1,5 @@ # © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK -from primaite.simulator.system.services.service import ServiceOperatingState +from primaite.simulator.system.services.service import Service, ServiceOperatingState from primaite.simulator.system.software import SoftwareHealthState @@ -92,3 +92,21 @@ def test_service_fix(service): assert service.health_state_actual == SoftwareHealthState.FIXING service.apply_timestep(2) assert service.health_state_actual == SoftwareHealthState.GOOD + + +def test_service_state_validator(service): + """Test the service state validator.""" + validator = Service._StateValidator(service=service, state=ServiceOperatingState.STOPPED) + assert validator(request=[], context={}) # service is stopped + service.start() + assert validator(request=[], context={}) is False # service is running - expecting stopped + + validator = Service._StateValidator(service=service, state=ServiceOperatingState.RUNNING) + assert validator(request=[], context={}) # service is running + service.pause() + assert validator(request=[], context={}) is False # service is paused - expecting running + + validator = Service._StateValidator(service=service, state=ServiceOperatingState.PAUSED) + assert validator(request=[], context={}) # service is paused + service.resume() + assert validator(request=[], context={}) is False # service is running - expecting paused