diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 0ac29c9..05ce4f4 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -1,9 +1,12 @@ +""" +conftest module +""" +from moto import mock_aws import pytest from utilities.classes.sqs_client import SQSClient from utilities.classes.log import CustomLogger from utilities.settings import QUEUE_NAME, SQS_BUCKET, REPORT_DIR from utilities import os_funcs as cmd -from moto import mock_aws def pytest_addoption(parser: 'pytest.Parser') -> None: """ @@ -12,16 +15,16 @@ def pytest_addoption(parser: 'pytest.Parser') -> None: Args: parser (pytest.Parser): The pytest parser object. """ - parser.addoption("--mock-aws", - action="store", + parser.addoption("--mock-aws", + action="store", default="True", choices=["True", "False"], type=str, help="Boolean to indicate if AWS should be mocked" ) -@pytest.fixture(scope='module') -def mock_aws_flag(request: 'pytest.FixtureRequest') -> bool: +@pytest.fixture(scope='module', name='mock_aws_flag') +def get_mock_aws_flag(request: 'pytest.FixtureRequest') -> bool: """ Fixture to retrieve the value of the --mock-aws option. @@ -32,12 +35,12 @@ def mock_aws_flag(request: 'pytest.FixtureRequest') -> bool: bool: Boolean indicating whether AWS should be mocked. """ mock_aws_value = request.config.getoption("--mock-aws") - mock_aws_flag = mock_aws_value == "True" + mock_aws_flag_value = mock_aws_value == "True" - return mock_aws_flag + return mock_aws_flag_value -@pytest.fixture(scope='module') -def log() -> CustomLogger: +@pytest.fixture(scope='module', name='log') +def get_log() -> CustomLogger: """ Fixture to create a CustomLogger instance. @@ -57,7 +60,7 @@ def setup(request: 'pytest.FixtureRequest', mock_aws_flag: bool, log: CustomLogg log (CustomLogger): A CustomLogger instance. """ log.info(f"AWS Mock Flag: {mock_aws_flag}") - + if mock_aws_flag: # Setup mocked AWS environment log.info("Creating mocked SQS client") @@ -94,8 +97,8 @@ def sqs_cli(mock_aws_flag: bool, log: CustomLogger) -> SQSClient: Returns: SQSClient: An SQSClient instance. """ - sqs_cli = SQSClient(log=log, bucket=SQS_BUCKET, mock_aws_flag=mock_aws_flag) - sqs_cli.create_queue(QUEUE_NAME) - sqs_cli.get_queue_url(QUEUE_NAME) + sqs_client_instance = SQSClient(log=log, bucket=SQS_BUCKET, mock_aws_flag=mock_aws_flag) + sqs_client_instance.create_queue(QUEUE_NAME) + sqs_client_instance.get_queue_url(QUEUE_NAME) - return sqs_cli + return sqs_client_instance diff --git a/tests/step_defs/test_messages_steps.py b/tests/step_defs/test_messages_steps.py index b3554c5..bf568de 100644 --- a/tests/step_defs/test_messages_steps.py +++ b/tests/step_defs/test_messages_steps.py @@ -1,12 +1,15 @@ -from pytest_bdd import scenarios, given, when, then +""" +steps to scenarios of cars_stream_processing feature +""" import json +from pytest_bdd import scenarios, given, when, then from utilities.settings import PROJECT_DIR # Load feature files for pytest-bdd scenarios('../features/cars_stream_processing.feature') # Given Step -@given('a list of cars are added to car queue', target_fixture='added_cars') +@given('a list of cars are added to car queue', target_fixture='cars_list') def added_cars(sqs_cli: 'SQSClient', log: 'CustomLogger') -> list: """ Given step to add a list of cars to the car queue. @@ -19,8 +22,10 @@ def added_cars(sqs_cli: 'SQSClient', log: 'CustomLogger') -> list: list: List of cars added to the queue. """ log.info("######## Start Step: 'Given a list of cars are added to car queue' ########") - f = open(PROJECT_DIR + "\\test-data\\cars.json", "r") - cars = json.loads(f.read()) + #f = open(PROJECT_DIR + "\\test-data\\cars.json", "r") + #cars = json.loads(f.read()) + with open(PROJECT_DIR + "\\test-data\\cars.json", "r", encoding='utf-8') as f: + cars = json.loads(f.read()) for car in cars: car_details = car["car detail"] @@ -36,7 +41,7 @@ def added_cars(sqs_cli: 'SQSClient', log: 'CustomLogger') -> list: return cars # When Step -@when("the queue list is returned", target_fixture='queue_list') +@when("the queue list is returned", target_fixture='messages') def queue_list(sqs_cli: 'SQSClient', log: 'CustomLogger') -> dict: """ When step to return the queue list. @@ -58,38 +63,42 @@ def queue_list(sqs_cli: 'SQSClient', log: 'CustomLogger') -> dict: # Then Step @then("the list contains the cars added") -def assert_response_code(sqs_cli: 'SQSClient', added_cars: list, queue_list: dict, log: 'CustomLogger') -> None: +def assert_response_code(sqs_cli: 'SQSClient', + cars_list: list, messages: dict, log: 'CustomLogger') -> None: """ Then step to assert that the list contains the cars added. Args: sqs_cli (SQSClient): An instance of SQSClient. - added_cars (list): List of cars added to the queue. - queue_list (dict): Queue list. + cars_list (list): List of cars added to the queue. + messages (dict): Queue list. log (CustomLogger): A CustomLogger instance. """ log.info("######## Start Step: 'Then the list contains the cars added' ########") messages_count = 0 - for message in queue_list["Messages"]: + for message in messages["Messages"]: in_message_id = message["MessageId"] body = message["Body"] receipt_handle = message["ReceiptHandle"] log.info(f"message body: {message}") - for car in added_cars: + for car in cars_list: car_details = car["car detail"] out_message_id = car["id"] if in_message_id == out_message_id: - - assert car_details == json.loads(body), f"body of the message {in_message_id} doesn't match car detail" + error_msg = f"body of the message {in_message_id} doesn't match car detail" + assert car_details == json.loads(body), error_msg log.info(f"delete message with id {in_message_id}") sqs_cli.delete_message(receipt_handle) messages_count += 1 - assert len(added_cars) == messages_count, f"Couldn't find all messages sent. Were sent {len(added_cars)} msgs, but found only {messages_count} msgs" + error_messages = f"""Couldn't find all messages sent. + Were sent {len(cars_list)} msgs, + but found only {messages_count} msgs""" + assert len(cars_list) == messages_count, error_messages log.info("######## End Step: 'Then the list contains the cars added' ########") diff --git a/utilities/classes/log.py b/utilities/classes/log.py index e2b6d1b..3eb6367 100644 --- a/utilities/classes/log.py +++ b/utilities/classes/log.py @@ -1,10 +1,28 @@ +""" +A custom logger class that logs messages to both console and file with timed rotation. +""" import logging import re from logging import handlers, Logger class CustomLogger(Logger): + """ + A custom logger class that logs messages to both console and file with timed rotation. + This class extends the standard Logger class + from the logging module and provides additional functionality + for logging messages to both console and file. Log files are rotated daily, + and old log files are automatically + deleted after a specified number of days. + + Attributes: + log_folder (str): The directory where log files will be stored. + backupCount_days (int): The number of days to keep backup log files. + + Methods: + __init__: Initializes the custom logger. + """ def __init__(self, log_folder: str, backupCount_days: int = 5): """ Initialize the CustomLogger. @@ -35,4 +53,4 @@ def __init__(self, log_folder: str, backupCount_days: int = 5): file_handler.suffix = '%Y_%m_%d.log' file_handler.extMatch = re.compile(r"^\d{4}_\d{2}_\d{2}.log$") file_handler.setFormatter(formatter) - self.addHandler(file_handler) \ No newline at end of file + self.addHandler(file_handler) diff --git a/utilities/classes/sqs_client.py b/utilities/classes/sqs_client.py index 3bb3e9b..b946574 100644 --- a/utilities/classes/sqs_client.py +++ b/utilities/classes/sqs_client.py @@ -1,10 +1,41 @@ +""" +SQSClient module + +This module contains the SQSClient class which provides methods for interacting with Amazon SQS. + +Classes: + SQSClient: A class for interacting with Amazon SQS. + +""" +import json import boto3 from botocore.exceptions import ClientError -import json from utilities.settings import LOCALHOST, REGION_NAME class SQSClient: - def __init__(self, log: 'CustomLogger', bucket: str, mock_aws_flag: bool, host: str = LOCALHOST, region_name: str = REGION_NAME): + """ + A class for interacting with Amazon SQS. + + Attributes: + log (CustomLogger): Logger object. + bucket_name (str): Name of the AWS bucket. + host (str): Host URL. + mock_aws_flag (bool): Flag indicating whether to mock AWS or not. + client (boto3.client): SQS client object. + queue_url (str): URL of the SQS queue. + + Methods: + __init__: Initializes the SQSClient. + create_client: Creates an SQS client based on mock_aws_flag. + create_queue: Creates an SQS queue. + get_queue_url: Gets the URL of an SQS queue. + send_message: Sends a message to the SQS queue. + receive_messages: Receives messages from the SQS queue. + delete_message: Deletes a message from the SQS queue. + """ + + def __init__(self, log: 'CustomLogger', bucket: str, + mock_aws_flag: bool, host: str = LOCALHOST): """ Initialize SQSClient. @@ -13,12 +44,11 @@ def __init__(self, log: 'CustomLogger', bucket: str, mock_aws_flag: bool, host: bucket (str): Name of the AWS bucket. mock_aws_flag (bool): Flag indicating whether to mock AWS or not. host (str, optional): Host URL. Defaults to LOCALHOST. - region_name (str, optional): AWS region name. Defaults to REGION_NAME. """ self.log = log self.bucket_name = bucket self.host = host - self.region_name = region_name + self.region_name = REGION_NAME self.mock_aws_flag = mock_aws_flag self.client = self.create_client() self.queue_url = '' @@ -31,9 +61,14 @@ def create_client(self) -> boto3.client: boto3.client: SQS client object. """ if self.mock_aws_flag: - return boto3.client(self.bucket_name, region_name=self.region_name) - else: - return boto3.client(self.bucket_name, endpoint_url=self.host, region_name=self.region_name) + return boto3.client(self.bucket_name, + region_name=self.region_name + ) + + return boto3.client(self.bucket_name, + endpoint_url=self.host, + region_name=self.region_name + ) def create_queue(self, queue_name: str) -> None: """ @@ -82,7 +117,8 @@ def send_message(self, car: dict) -> dict: """ try: message = car - response = self.client.send_message(QueueUrl=self.queue_url, MessageBody=json.dumps(message)) + response = self.client.send_message(QueueUrl=self.queue_url, + MessageBody=json.dumps(message)) self.log.info("Message sent") return response except ClientError as error: @@ -97,7 +133,9 @@ def receive_messages(self) -> dict: dict: Messages received from the SQS service. """ try: - messages = self.client.receive_message(QueueUrl=self.queue_url, MaxNumberOfMessages=10, WaitTimeSeconds=10) + messages = self.client.receive_message(QueueUrl=self.queue_url, + MaxNumberOfMessages=10, + WaitTimeSeconds=10) self.log.info("Messages received") return messages except ClientError as error: