blob: e78e9767a15822d4a2e63330ccbe7cb9e7794f5b [file] [log] [blame] [edit]
# pylint: disable= R1710,W1203, W0612, W0718
"""Client agent for the DUT machine to run test and connect with the server
agent"""
import argparse
import ctypes
import logging
import os
import shlex
import socket
import subprocess
import shutil
import time
import platform
SYSTEM = platform.system().lower()
IN_PROGRESS_RESULTS_FILE = "in_progress_results.txt"
RESULTS_FILE = "DUT_automation_results.txt"
def logging_definition():
"""Configure logging to write logs to a file."""
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
def logging_setup():
"""Setup file handler to store the logs inside it.
Returns:
logging file handler.
"""
results_file_handler = logging.FileHandler(IN_PROGRESS_RESULTS_FILE)
results_file_handler.setLevel(logging.INFO)
results_file_handler.setFormatter(
logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
)
logging.getLogger().addHandler(results_file_handler)
return results_file_handler
def search_file_recursive(directory, file_name):
"""Searches for a file within a directory and its subdirectories.
Args:
directory: The directory to search within.
file_name: The name of the file to search for.
Returns:
path of the file within the directory.
"""
try:
for root, dirs, files in os.walk(directory):
if file_name in files:
return os.path.join(root, file_name)
raise FileNotFoundError(
f"Error! Cannot find {file_name} in {directory} " f"directory"
)
except FileNotFoundError as e:
logging.error(e)
except Exception as e:
logging.error(e)
def install_requirements_file(code_directory):
"""Helper function to install the contents of the requirements.txt file.
Args:
code_directory: The directory that contains the requirements.txt.
"""
try:
requirements_file_path = search_file_recursive(
code_directory, "requirements.txt"
)
logging.info("Installing the requirements file")
if SYSTEM == "linux":
command = f'python3 -m pip install -r "{requirements_file_path}"'
subprocess.run(
command, check=True, capture_output=True, text=True, shell=True
)
else:
command = f'pip install -r "{requirements_file_path}"'
subprocess.run(
command, shell=True, check=True, capture_output=True, text=True
)
logging.info("Finish installing the requirements file successfully")
except subprocess.CalledProcessError as e:
logging.error(f"Error while installing the requirements file: {e}")
except FileNotFoundError as e:
logging.error(e)
def run_automation_file(automation_code_directory, automation_file):
"""This function is responsible for running the use case code by
executed its logic.
Args:
automation_code_directory: The name of the directory that contains the
code.
automation_file: The path of the automation file that contains the use
case logic.
"""
try:
automation_file_path = search_file_recursive(
automation_code_directory, automation_file
)
full_path = automation_file_path
if SYSTEM == "linux":
run_command = ["python3", full_path]
subprocess.run(run_command, check=True)
else:
run_command = ["python", full_path]
subprocess.run(run_command, shell=True, check=True)
except subprocess.CalledProcessError as e:
logging.error(f"Error while running the automation file: {e}")
except FileNotFoundError as e:
logging.error(f"Error! Cannot find the automation file: {e}")
def extract_command_values(command_string):
"""Helper function to extract the arguments from the command string.
Args:
command_string: The command received from the controller machine.
Returns:
A tuple containing the status, remote directory, and file name
extracted from the command string.
"""
parser = argparse.ArgumentParser()
parser.add_argument("--status", required=True)
parser.add_argument("-d", "--remote_directory", required=True)
parser.add_argument("-f", "--file_name", required=True)
input_list = shlex.split(command_string)
args = parser.parse_args(input_list)
return args.status, args.remote_directory, args.file_name
def delete_file(file_name):
"""Helper function to delete a given file from the local machine.
Args:
file_name: The name of the file to be deleted.
"""
if os.path.exists(file_name):
os.remove(file_name)
logging.info(f"File {file_name} deleted successfully")
else:
logging.warning(f"Results file '{file_name}' not found")
def teardown_automation(automation_code_directory):
"""
Teardown function to clean up resources after automation execution.
Args:
automation_code_directory (str): Path to the directory containing
automation code.
"""
try:
# Remove the automation code directory
if os.path.exists(automation_code_directory):
logging.info("Deleting Automation Code directory")
shutil.rmtree(automation_code_directory)
logging.info("Successfully deleted Automation Code directory")
else:
logging.warning(
f"Automation Code directory '{automation_code_directory}' not found"
)
time.sleep(3)
delete_file(RESULTS_FILE)
except Exception as e:
logging.error(f"Error occurred during teardown: {e}")
def set_system_suspend_state():
"""Helper function to put the device in the sleep mode.
This function will simulate the process that we execute it when sleep
choice selected from the start menu.
"""
system_power_state = ctypes.c_int
suspend = 0
ctypes.windll.powrprof.SetSuspendState(system_power_state(suspend), 0, 0)
def read_file_content(file_path):
"""Helper function to read the content of a given file path.
Args:
file_path: the path of the required file to be read.
Returns:
The content of the given file.
"""
try:
with open(str(file_path), "r", encoding="utf-8") as file:
return file.readlines()
except FileNotFoundError:
return ["File not found."]
def append_to_results_file(file_name, code_directory):
"""Helper function to append the content of a given file to the results
file.
Args:
file_name : The name of the file to be appended.
code_directory: The directory of the automation tests.
"""
full_path = search_file_recursive(rf"{code_directory}/out", file_name)
file_content = read_file_content(full_path)
with open(IN_PROGRESS_RESULTS_FILE, "a", encoding="utf-8") as file:
file.writelines(file_content)
def rename_file():
"""Helper function to rename a specific file."""
try:
os.rename(IN_PROGRESS_RESULTS_FILE, RESULTS_FILE)
except FileNotFoundError:
print(f"File {IN_PROGRESS_RESULTS_FILE} not found")
except FileExistsError:
print(f"File {RESULTS_FILE} already exists")
def main():
"""The entry point of the target agent that will:
1. Set up the logging and logging file handler.
2. Listen to the SSH request from the server machine.
3. Receive command from the server machine.
4. Install the requirements file.
5. Run the use case automation test based on the received status.
6. Delete the files and directories for the automation test.
"""
host = ""
socket_port = 8888
logging_definition()
logs_file_handler = logging_setup()
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket:
server_socket.bind((host, socket_port))
server_socket.listen()
logging.info(f"Server is listening on port {socket_port}")
while True:
conn, addr = server_socket.accept()
with conn:
logging.info(f"Connected by {addr}")
server_command = conn.makefile().readline().strip()
logging.info("Received command from the server agent.")
if ("--status" and "-d" and "-f") in server_command:
status, code_directory, automation_file = (
extract_command_values(server_command)
)
install_requirements_file(code_directory=code_directory)
if status == "current":
logging.info(
f"Started test '{automation_file}' from the "
"current mode"
)
run_automation_file(code_directory, automation_file)
logging.info(f"Finish executing {automation_file} test")
elif status == "sleep":
logging.info(
f"Started test {automation_file} from sleep mode"
)
logging.info("Entering sleep mode")
time_before_sleep = time.time()
set_system_suspend_state()
time_after_wakeup = time.time()
logging.info("Waking up from sleep mode")
logging.info(f"Started test {automation_file}")
run_automation_file(code_directory, automation_file)
time_from_wakeup_to_finish = (
time.time() - time_after_wakeup
)
time_from_sleep_to_finish = (
time.time() - time_before_sleep
)
logging.info(
"Time from wake up until finish the test = "
f"{time_from_wakeup_to_finish}"
)
logging.info(
"Time from entering sleep mode until finish the "
f"test = {time_from_sleep_to_finish}"
)
logging.info(f"Finish executing {automation_file} test")
time.sleep(5)
append_to_results_file("logs.log", code_directory)
append_to_results_file("results.log", code_directory)
logs_file_handler.close()
rename_file()
logs_file_handler.close()
teardown_automation(code_directory)
return "Finish DUT Automation Code"
if __name__ == "__main__":
main()