diff --git a/eox_nelp/pearson_vue/rti_backend.py b/eox_nelp/pearson_vue/rti_backend.py index 69eb46ad..86b0eb60 100644 --- a/eox_nelp/pearson_vue/rti_backend.py +++ b/eox_nelp/pearson_vue/rti_backend.py @@ -6,6 +6,7 @@ RealTimeImport: Class for managing RTI operations and executing the pipeline. """ import importlib +from abc import ABC, abstractmethod from eox_nelp.pearson_vue.exceptions import PearsonBaseError from eox_nelp.pearson_vue.pipeline import ( @@ -23,30 +24,39 @@ ) -class RealTimeImport: +class AbstractBackend(ABC): """ - Class for managing RTI (Real Time Import) operations and executing the pipeline. + Base class for managing backend operations and executing pipelines. + + This class provides the core functionality to manage backend data and run a sequence of operations, + defined as a pipeline, to process the data. Subclasses must override the `get_pipeline` method + to provide specific pipeline functions. Attributes: backend_data (dict): A dictionary containing backend-specific data. Methods: - run_pipeline(): Executes the RTI pipeline by iterating through the pipeline functions. - get_pipeline(): Returns the RTI pipeline, which is a list of functions to be executed. + run_pipeline(): Executes the pipeline by iterating through the pipeline functions. + get_pipeline(): Returns the pipeline, which is a list of functions to be executed (abstract method). + handle_error(exception: Exception, failed_step_pipeline: str): Handles errors during pipeline execution. """ def __init__(self, **kwargs): """ - Initializes the RealTimeImport instance with the provided keyword arguments. + Initializes the AbstractBackend instance with the provided keyword arguments. Args: - **kwargs: Additional keyword arguments to configure the RealTimeImport instance. + **kwargs: Additional keyword arguments to configure the AbstractBackend instance. """ self.backend_data = kwargs.copy() def run_pipeline(self): """ - Executes the RTI pipeline by iterating through the pipeline functions. + Executes the pipeline by iterating through the pipeline functions. + + This method retrieves the pipeline using the `get_pipeline` method and executes each function + in the pipeline sequentially. If an error occurs during the execution of a function, it calls + `handle_error` method to handle the error and stops the pipeline execution. """ pipeline = self.get_pipeline() pipeline_index = self.backend_data.get("pipeline_index", 0) @@ -56,13 +66,7 @@ def run_pipeline(self): try: result = func(**self.backend_data) or {} except PearsonBaseError as pearson_error: - tasks = importlib.import_module("eox_nelp.pearson_vue.tasks") - tasks.rti_error_handler_task.delay( - failed_step_pipeline=func.__name__, - exception_dict=pearson_error.to_dict(), - course_id=self.backend_data.get("course_id"), - user_id=self.backend_data.get("user_id"), - ) + self.handle_error(pearson_error, func.__name__) break self.backend_data.update(result) @@ -70,6 +74,77 @@ def run_pipeline(self): self.backend_data["pipeline_index"] = len(pipeline) - 1 break + @abstractmethod + def get_pipeline(self): + """ + Returns the pipeline, which is a list of functions to be executed. + + Subclasses must override this method to provide the specific functions to be executed in the pipeline. + + Returns: + list: A list of functions representing the pipeline. + """ + + @abstractmethod + def handle_error(self, exception, failed_step_pipeline): + """ + Handles errors during pipeline execution. + + Args: + exception (PearsonBaseError): The exception that was raised. + failed_step_pipeline (str): The name of the pipeline step where the error occurred. + """ + + +class ErrorRealTimeImportHandler(AbstractBackend): + """Class for managing validation error pipe executing the pipeline for data validation.""" + + def handle_error(self, exception, failed_step_pipeline): + """ + Handles errors during pipeline execution. + + Args: + exception (Exception): The exception that was raised. + failed_step_pipeline (str): The name of the pipeline step where the error occurred. + """ + + def get_pipeline(self): + """ + Returns the error validation pipeline, which is a list of functions to be executed. + """ + return [ + audit_pearson_error, + ] + + +class RealTimeImport(AbstractBackend): + """ + Class for managing RTI (Real Time Import) operations and executing the pipeline. + + Attributes: + backend_data (dict): A dictionary containing backend-specific data. + + Methods: + run_pipeline(): Executes the RTI pipeline by iterating through the pipeline functions. + get_pipeline(): Returns the RTI pipeline, which is a list of functions to be executed. + """ + + def handle_error(self, exception, failed_step_pipeline): + """ + Handles errors during pipeline execution. + + Args: + exception (Exception): The exception that was raised. + failed_step_pipeline (str): The name of the pipeline step where the error occurred. + """ + tasks = importlib.import_module("eox_nelp.pearson_vue.tasks") + tasks.rti_error_handler_task.delay( + failed_step_pipeline=failed_step_pipeline, + exception_dict=exception.to_dict(), + course_id=self.backend_data.get("course_id"), + user_id=self.backend_data.get("user_id"), + ) + def get_pipeline(self): """ Returns the RTI pipeline, which is a list of functions to be executed. @@ -90,6 +165,7 @@ def get_pipeline(self): class ExamAuthorizationDataImport(RealTimeImport): """Class for EAD requests (Exam Authorization Data operations) and executing the pipeline.""" + def get_pipeline(self): """ Returns the EAD pipeline, which is a list of functions to be executed. @@ -106,6 +182,7 @@ def get_pipeline(self): class CandidateDemographicsDataImport(RealTimeImport): """Class for CDD requests (Candidate Demographics Data operations) and executing the pipeline.""" + def get_pipeline(self): """ Returns the CDD pipeline, which is a list of functions to be executed. @@ -117,14 +194,3 @@ def get_pipeline(self): check_service_availability, import_candidate_demographics, ] - - -class ErrorRealTimeImportHandler(RealTimeImport): - """Class for managing validation error pipe executing the pipeline for data validation.""" - def get_pipeline(self): - """ - Returns the error validation pipeline, which is a list of functions to be executed. - """ - return [ - audit_pearson_error, - ] diff --git a/eox_nelp/pearson_vue/tests/test_rti_backend.py b/eox_nelp/pearson_vue/tests/test_rti_backend.py index e3dbe27e..57a118da 100644 --- a/eox_nelp/pearson_vue/tests/test_rti_backend.py +++ b/eox_nelp/pearson_vue/tests/test_rti_backend.py @@ -16,14 +16,12 @@ ) -@ddt -class TestRealTimeImport(unittest.TestCase): +class TestAbstractBackendMixin: """ - Unit tests for the RealTimeImport class. + Unit tests for the AbstracBackend subclasses. """ - rti_backend_class = RealTimeImport - def setUp(self): + def setUp(self): # pylint: disable=invalid-name """ Set up the test environment. """ @@ -145,6 +143,27 @@ def test_safely_pipeline_termination(self): }, ) + def test_get_pipeline(self): + """ + Test the retrieval of the RTI pipeline. + + Expected behavior: + - Method return a list instance + - All the pipeline items are callable. + """ + pipeline = self.rti.get_pipeline() + + self.assertIsInstance(pipeline, list) + self.assertTrue(all(callable(func) for func in pipeline)) + + +@ddt +class TestRealTimeImport(TestAbstractBackendMixin, unittest.TestCase): + """ + Unit tests for the RealTimeImport class. + """ + rti_backend_class = RealTimeImport + @data( PearsonValidationError(inspect.currentframe(), "error: ['String to short.']"), PearsonKeyError(inspect.currentframe(), "eligibility_appt_date_first"), @@ -198,19 +217,6 @@ def test_launch_validation_error_pipeline(self, pearson_error, rti_error_handler course_id=None, ) - def test_get_pipeline(self): - """ - Test the retrieval of the RTI pipeline. - - Expected behavior: - - Method return a list instance - - All the pipeline items are callable. - """ - pipeline = self.rti.get_pipeline() - - self.assertIsInstance(pipeline, list) - self.assertTrue(all(callable(func) for func in pipeline)) - class TestExamAuthorizationDataImport(TestRealTimeImport): """ @@ -226,7 +232,7 @@ class TestCandidateDemographicsDataImport(TestRealTimeImport): rti_backend_class = CandidateDemographicsDataImport -class TestErrorRealTimeImportHandler(TestRealTimeImport): +class TestErrorRealTimeImportHandler(TestAbstractBackendMixin, unittest.TestCase): """ Unit tests for the rti_backend class. """