#2350: add num_access, num_file_deletions and num_creations to file system
This commit is contained in:
@@ -38,6 +38,8 @@ class File(FileSystemItemABC):
|
||||
"The Path if real is True."
|
||||
sim_root: Optional[Path] = None
|
||||
"Root path of the simulation."
|
||||
num_access: int = 0
|
||||
"Number of times the file was accessed in the current step."
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
@@ -93,11 +95,23 @@ class File(FileSystemItemABC):
|
||||
return os.path.getsize(self.sim_path)
|
||||
return self.sim_size
|
||||
|
||||
def apply_timestep(self, timestep: int) -> None:
|
||||
"""
|
||||
Apply a timestep to the file.
|
||||
|
||||
:param timestep: The current timestep of the simulation.
|
||||
"""
|
||||
super().apply_timestep(timestep=timestep)
|
||||
|
||||
# reset the number of accesses to 0
|
||||
self.num_access = 0
|
||||
|
||||
def describe_state(self) -> Dict:
|
||||
"""Produce a dictionary describing the current state of this object."""
|
||||
state = super().describe_state()
|
||||
state["size"] = self.size
|
||||
state["file_type"] = self.file_type.name
|
||||
state["num_access"] = self.num_access
|
||||
return state
|
||||
|
||||
def scan(self) -> None:
|
||||
@@ -106,6 +120,7 @@ class File(FileSystemItemABC):
|
||||
self.sys_log.error(f"Unable to scan deleted file {self.folder_name}/{self.name}")
|
||||
return
|
||||
|
||||
self.num_access += 1 # file was accessed
|
||||
path = self.folder.name + "/" + self.name
|
||||
self.sys_log.info(f"Scanning file {self.sim_path if self.sim_path else path}")
|
||||
self.visible_health_status = self.health_status
|
||||
@@ -160,6 +175,7 @@ class File(FileSystemItemABC):
|
||||
if self.health_status == FileSystemItemHealthStatus.CORRUPT:
|
||||
self.health_status = FileSystemItemHealthStatus.GOOD
|
||||
|
||||
self.num_access += 1 # file was accessed
|
||||
path = self.folder.name + "/" + self.name
|
||||
self.sys_log.info(f"Repaired file {self.sim_path if self.sim_path else path}")
|
||||
|
||||
@@ -173,6 +189,7 @@ class File(FileSystemItemABC):
|
||||
if self.health_status == FileSystemItemHealthStatus.GOOD:
|
||||
self.health_status = FileSystemItemHealthStatus.CORRUPT
|
||||
|
||||
self.num_access += 1 # file was accessed
|
||||
path = self.folder.name + "/" + self.name
|
||||
self.sys_log.info(f"Corrupted file {self.sim_path if self.sim_path else path}")
|
||||
|
||||
@@ -185,6 +202,7 @@ class File(FileSystemItemABC):
|
||||
if self.health_status == FileSystemItemHealthStatus.CORRUPT:
|
||||
self.health_status = FileSystemItemHealthStatus.GOOD
|
||||
|
||||
self.num_access += 1 # file was accessed
|
||||
path = self.folder.name + "/" + self.name
|
||||
self.sys_log.info(f"Restored file {self.sim_path if self.sim_path else path}")
|
||||
|
||||
@@ -194,5 +212,6 @@ class File(FileSystemItemABC):
|
||||
self.sys_log.error(f"Unable to delete an already deleted file {self.folder_name}/{self.name}")
|
||||
return
|
||||
|
||||
self.num_access += 1 # file was accessed
|
||||
self.deleted = True
|
||||
self.sys_log.info(f"File deleted {self.folder_name}/{self.name}")
|
||||
|
||||
@@ -27,6 +27,10 @@ class FileSystem(SimComponent):
|
||||
"Instance of SysLog used to create system logs."
|
||||
sim_root: Path
|
||||
"Root path of the simulation."
|
||||
num_file_creations: int = 0
|
||||
"Number of file creations in the current step."
|
||||
num_file_deletions: int = 0
|
||||
"Number of file deletions in the current step."
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
@@ -248,6 +252,8 @@ class FileSystem(SimComponent):
|
||||
)
|
||||
folder.add_file(file)
|
||||
self._file_request_manager.add_request(name=file.name, request_type=RequestType(func=file._request_manager))
|
||||
# increment file creation
|
||||
self.num_file_creations += 1
|
||||
return file
|
||||
|
||||
def get_file(self, folder_name: str, file_name: str, include_deleted: Optional[bool] = False) -> Optional[File]:
|
||||
@@ -308,6 +314,8 @@ class FileSystem(SimComponent):
|
||||
if folder:
|
||||
file = folder.get_file(file_name)
|
||||
if file:
|
||||
# increment file creation
|
||||
self.num_file_deletions += 1
|
||||
folder.remove_file(file)
|
||||
|
||||
def delete_file_by_id(self, folder_uuid: str, file_uuid: str):
|
||||
@@ -337,15 +345,14 @@ class FileSystem(SimComponent):
|
||||
"""
|
||||
file = self.get_file(folder_name=src_folder_name, file_name=src_file_name)
|
||||
if file:
|
||||
src_folder = file.folder
|
||||
|
||||
# remove file from src
|
||||
src_folder.remove_file(file)
|
||||
self.delete_file(folder_name=file.folder_name, file_name=file.name)
|
||||
dst_folder = self.get_folder(folder_name=dst_folder_name)
|
||||
if not dst_folder:
|
||||
dst_folder = self.create_folder(dst_folder_name)
|
||||
# add file to dst
|
||||
dst_folder.add_file(file)
|
||||
self.num_file_creations += 1
|
||||
if file.real:
|
||||
old_sim_path = file.sim_path
|
||||
file.sim_path = file.sim_root / file.path
|
||||
@@ -373,6 +380,10 @@ class FileSystem(SimComponent):
|
||||
folder_name=dst_folder.name,
|
||||
**file.model_dump(exclude={"uuid", "folder_id", "folder_name", "sim_path"}),
|
||||
)
|
||||
self.num_file_creations += 1
|
||||
# increment access counter
|
||||
file.num_access += 1
|
||||
|
||||
dst_folder.add_file(file_copy, force=True)
|
||||
|
||||
if file.real:
|
||||
@@ -390,12 +401,20 @@ class FileSystem(SimComponent):
|
||||
state = super().describe_state()
|
||||
state["folders"] = {folder.name: folder.describe_state() for folder in self.folders.values()}
|
||||
state["deleted_folders"] = {folder.name: folder.describe_state() for folder in self.deleted_folders.values()}
|
||||
state["num_file_creations"] = self.num_file_creations
|
||||
state["num_file_deletions"] = self.num_file_deletions
|
||||
return state
|
||||
|
||||
def apply_timestep(self, timestep: int) -> None:
|
||||
"""Apply time step to FileSystem and its child folders and files."""
|
||||
super().apply_timestep(timestep=timestep)
|
||||
|
||||
# reset number of file creations
|
||||
self.num_file_creations = 0
|
||||
|
||||
# reset number of file deletions
|
||||
self.num_file_deletions = 0
|
||||
|
||||
# apply timestep to folders
|
||||
for folder_id in self.folders:
|
||||
self.folders[folder_id].apply_timestep(timestep=timestep)
|
||||
|
||||
@@ -131,6 +131,7 @@ class Folder(FileSystemItemABC):
|
||||
file.scan()
|
||||
if file.visible_health_status == FileSystemItemHealthStatus.CORRUPT:
|
||||
self.visible_health_status = FileSystemItemHealthStatus.CORRUPT
|
||||
self.visible_health_status = self.health_status
|
||||
|
||||
def _reveal_to_red_timestep(self) -> None:
|
||||
"""Apply reveal to red timestep."""
|
||||
|
||||
@@ -59,6 +59,16 @@ class Application(IOSoftware):
|
||||
)
|
||||
return state
|
||||
|
||||
def apply_timestep(self, timestep: int) -> None:
|
||||
"""
|
||||
Apply a timestep to the application.
|
||||
|
||||
:param timestep: The current timestep of the simulation.
|
||||
"""
|
||||
super().apply_timestep(timestep=timestep)
|
||||
|
||||
self.num_executions = 0 # reset number of executions
|
||||
|
||||
def _can_perform_action(self) -> bool:
|
||||
"""
|
||||
Checks if the application can perform actions.
|
||||
|
||||
@@ -76,6 +76,8 @@ class DatabaseClient(Application):
|
||||
if not self._can_perform_action():
|
||||
return False
|
||||
|
||||
self.num_executions += 1 # trying to connect counts as an execution
|
||||
|
||||
if not connection_id:
|
||||
connection_id = str(uuid4())
|
||||
|
||||
|
||||
@@ -194,6 +194,8 @@ class DataManipulationBot(Application):
|
||||
"""
|
||||
if not self._can_perform_action():
|
||||
return
|
||||
|
||||
self.num_executions += 1
|
||||
if self.server_ip_address and self.payload:
|
||||
self.sys_log.info(f"{self.name}: Running")
|
||||
self._logon()
|
||||
|
||||
@@ -80,6 +80,8 @@ class WebBrowser(Application):
|
||||
if not self._can_perform_action():
|
||||
return False
|
||||
|
||||
self.num_executions += 1 # trying to connect counts as an execution
|
||||
|
||||
# reset latest response
|
||||
self.latest_response = HttpResponsePacket(status_code=HttpStatusCode.NOT_FOUND)
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.file_system.file import File
|
||||
from primaite.simulator.file_system.file_system import FileSystem
|
||||
from primaite.simulator.file_system.file_type import FileType
|
||||
from primaite.simulator.file_system.folder import Folder
|
||||
|
||||
|
||||
def test_create_folder_and_file(file_system):
|
||||
@@ -14,8 +16,15 @@ def test_create_folder_and_file(file_system):
|
||||
|
||||
assert len(file_system.get_folder("test_folder").files) == 1
|
||||
|
||||
assert file_system.num_file_creations == 1
|
||||
|
||||
assert file_system.get_folder("test_folder").get_file("test_file.txt")
|
||||
|
||||
file_system.apply_timestep(0)
|
||||
|
||||
# num file creations should reset
|
||||
assert file_system.num_file_creations == 0
|
||||
|
||||
file_system.show(full=True)
|
||||
|
||||
|
||||
@@ -23,24 +32,37 @@ def test_create_file_no_folder(file_system):
|
||||
"""Tests that creating a file without a folder creates a folder and sets that as the file's parent."""
|
||||
file = file_system.create_file(file_name="test_file.txt", size=10)
|
||||
assert len(file_system.folders) is 1
|
||||
assert file_system.num_file_creations == 1
|
||||
assert file_system.get_folder("root").get_file("test_file.txt") == file
|
||||
assert file_system.get_folder("root").get_file("test_file.txt").file_type == FileType.TXT
|
||||
assert file_system.get_folder("root").get_file("test_file.txt").size == 10
|
||||
|
||||
file_system.apply_timestep(0)
|
||||
|
||||
# num file creations should reset
|
||||
assert file_system.num_file_creations == 0
|
||||
|
||||
file_system.show(full=True)
|
||||
|
||||
|
||||
def test_delete_file(file_system):
|
||||
"""Tests that a file can be deleted."""
|
||||
file_system.create_file(file_name="test_file.txt")
|
||||
file = file_system.create_file(file_name="test_file.txt")
|
||||
assert len(file_system.folders) == 1
|
||||
assert len(file_system.get_folder("root").files) == 1
|
||||
|
||||
file_system.delete_file(folder_name="root", file_name="test_file.txt")
|
||||
assert file.num_access == 1
|
||||
assert file_system.num_file_deletions == 1
|
||||
assert len(file_system.folders) == 1
|
||||
assert len(file_system.get_folder("root").files) == 0
|
||||
assert len(file_system.get_folder("root").deleted_files) == 1
|
||||
|
||||
file_system.apply_timestep(0)
|
||||
|
||||
# num file deletions should reset
|
||||
assert file_system.num_file_deletions == 0
|
||||
|
||||
file_system.show(full=True)
|
||||
|
||||
|
||||
@@ -54,6 +76,7 @@ def test_delete_non_existent_file(file_system):
|
||||
|
||||
# deleting should not change how many files are in folder
|
||||
file_system.delete_file(folder_name="root", file_name="does_not_exist!")
|
||||
assert file_system.num_file_deletions == 0
|
||||
|
||||
# should still only be one folder
|
||||
assert len(file_system.folders) == 1
|
||||
@@ -96,6 +119,7 @@ def test_create_duplicate_file(file_system):
|
||||
|
||||
assert len(file_system.folders) is 2
|
||||
file_system.create_file(file_name="test_file.txt", folder_name="test_folder")
|
||||
assert file_system.num_file_creations == 1
|
||||
|
||||
assert len(file_system.get_folder("test_folder").files) == 1
|
||||
|
||||
@@ -103,6 +127,7 @@ def test_create_duplicate_file(file_system):
|
||||
file_system.create_file(file_name="test_file.txt", folder_name="test_folder")
|
||||
|
||||
assert len(file_system.get_folder("test_folder").files) == 1
|
||||
assert file_system.num_file_creations == 1
|
||||
|
||||
file_system.show(full=True)
|
||||
|
||||
@@ -136,13 +161,24 @@ def test_move_file(file_system):
|
||||
|
||||
assert len(file_system.get_folder("src_folder").files) == 1
|
||||
assert len(file_system.get_folder("dst_folder").files) == 0
|
||||
assert file_system.num_file_deletions == 0
|
||||
assert file_system.num_file_creations == 1
|
||||
|
||||
file_system.move_file(src_folder_name="src_folder", src_file_name="test_file.txt", dst_folder_name="dst_folder")
|
||||
assert file_system.num_file_deletions == 1
|
||||
assert file_system.num_file_creations == 2
|
||||
assert file.num_access == 1
|
||||
|
||||
assert len(file_system.get_folder("src_folder").files) == 0
|
||||
assert len(file_system.get_folder("dst_folder").files) == 1
|
||||
assert file_system.get_file("dst_folder", "test_file.txt").uuid == original_uuid
|
||||
|
||||
file_system.apply_timestep(0)
|
||||
|
||||
# num file creations and deletions should reset
|
||||
assert file_system.num_file_creations == 0
|
||||
assert file_system.num_file_deletions == 0
|
||||
|
||||
file_system.show(full=True)
|
||||
|
||||
|
||||
@@ -152,17 +188,25 @@ def test_copy_file(file_system):
|
||||
file_system.create_folder(folder_name="dst_folder")
|
||||
|
||||
file = file_system.create_file(file_name="test_file.txt", size=10, folder_name="src_folder", real=True)
|
||||
assert file_system.num_file_creations == 1
|
||||
original_uuid = file.uuid
|
||||
|
||||
assert len(file_system.get_folder("src_folder").files) == 1
|
||||
assert len(file_system.get_folder("dst_folder").files) == 0
|
||||
|
||||
file_system.copy_file(src_folder_name="src_folder", src_file_name="test_file.txt", dst_folder_name="dst_folder")
|
||||
assert file_system.num_file_creations == 2
|
||||
assert file.num_access == 1
|
||||
|
||||
assert len(file_system.get_folder("src_folder").files) == 1
|
||||
assert len(file_system.get_folder("dst_folder").files) == 1
|
||||
assert file_system.get_file("dst_folder", "test_file.txt").uuid != original_uuid
|
||||
|
||||
file_system.apply_timestep(0)
|
||||
|
||||
# num file creations should reset
|
||||
assert file_system.num_file_creations == 0
|
||||
|
||||
file_system.show(full=True)
|
||||
|
||||
|
||||
@@ -172,13 +216,17 @@ def test_get_file(file_system):
|
||||
file1: File = file_system.create_file(file_name="test_file.txt", folder_name="test_folder")
|
||||
file2: File = file_system.create_file(file_name="test_file2.txt", folder_name="test_folder")
|
||||
|
||||
folder.remove_file(file2)
|
||||
file_system.delete_file("test_folder", "test_file2.txt")
|
||||
# file 2 was accessed before being deleted
|
||||
assert file2.num_access == 1
|
||||
|
||||
assert file_system.get_file_by_id(file_uuid=file1.uuid, folder_uuid=folder.uuid) is not None
|
||||
assert file_system.get_file_by_id(file_uuid=file2.uuid, folder_uuid=folder.uuid) is None
|
||||
assert file_system.get_file_by_id(file_uuid=file2.uuid, folder_uuid=folder.uuid, include_deleted=True) is not None
|
||||
assert file_system.get_file_by_id(file_uuid=file2.uuid, include_deleted=True) is not None
|
||||
|
||||
assert file2.num_access == 1 # cannot access deleted file
|
||||
|
||||
file_system.delete_folder(folder_name="test_folder")
|
||||
assert file_system.get_file_by_id(file_uuid=file2.uuid, include_deleted=True) is not None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user