def test_no_failures(self): task = OperationObject() failing_task = RunWithFailure(task, fail_n_times=0) times_run = run_operation(failing_task) self.assertEqual(times_run, 1) self.assertEqual(task._times_called, 1)
def test_custom_exception_fails(self): task = RunWithFailure(OperationObject(), fail_n_times=2) for fname, run_with_custom_exceptions in test_cases(CUSTOM_EXCEPTION): with self.subTest(fx=fname), self.assertRaises( ControlledException ): run_with_custom_exceptions(task)
def _test_task_fails( self, fail_task_n_times: int, exception_cls: Type[Exception], expected_error_msg: Optional[str] = None, **deco_kwargs, ): for sut_deco in self.decorators_to_test: @sut_deco(**deco_kwargs) def test_run(task): return task.run() failing_task = RunWithFailure( OperationObject(), fail_n_times=fail_task_n_times, exception_cls=exception_cls, ) with self.subTest( decorator_tested=sut_deco, decorated=test_run, **deco_kwargs ), self.assertRaises(exception_cls) as cm: test_run(failing_task) if expected_error_msg: self.assertEqual(str(cm.exception), expected_error_msg)
def test_retry_custom_limit_ok(self): """Retry = 5, fail = 2, OK""" task = RunWithFailure(OperationObject(), fail_n_times=2) for fname, run_with_custom_retries_limit in test_cases(RETRIES_LIMIT): with self.subTest(tx=fname): result = run_with_custom_retries_limit(task) self.assertEqual(result, 3)
def test_fail_less_than_retry_limit(self): """Retry = 3, fail = 2 --> OK""" task = OperationObject() failing_task = RunWithFailure(task, fail_n_times=2) times_run = run_operation(failing_task) self.assertEqual(times_run, 3) self.assertEqual(task._times_called, 3)
def test_fail_less_than_retry_limit(self, test_function): """Retry = 3, fail = 2, should work""" task = OperationObject() failing_task = RunWithFailure(task, fail_n_times=2) times_run = test_function(failing_task) self.assertEqual(times_run, 3) self.assertEqual(task._times_called, 3)
def test_no_failures(self): task = OperationObject() failing_task = RunWithFailure(task, fail_n_times=0) for fname, run_operation in test_cases(RUN_OPERATION): with self.subTest(tx=fname): times_run = run_operation(failing_task) self.assertEqual(times_run, 1) self.assertEqual(task._times_called, 1)
def test_fail_equal_retry_limit(self): """Retry = fail = 3, will fail""" for fname, run_operation in test_cases(RUN_OPERATION): task = OperationObject() failing_task = RunWithFailure(task, fail_n_times=3) with self.subTest(fx=fname), self.assertRaises( ControlledException ): run_operation(failing_task)
def test_run_with_custom_parameters_controlled(self): task = RunWithFailure( OperationObject(), fail_n_times=3, exception_cls=AttributeError ) for fname, run_with_custom_parameters in test_cases(CUSTOM_PARAMETERS): with self.subTest(tx=fname): times_run = run_with_custom_parameters(task) self.assertEqual(times_run, 4)
def test_retry_custom_limit_fail(self): """Retry = 5, fail = 5, Fail""" for fname, run_with_custom_retries_limit in test_cases(RETRIES_LIMIT): t = OperationObject() task = RunWithFailure(t, fail_n_times=5) with self.subTest(fx=fname), self.assertRaises( ControlledException ): run_with_custom_retries_limit(task) self.assertEqual(t._times_called, 5)
def test_fail_less_than_retry_limit(self): """Retry = 3, fail = 2, should work""" task = OperationObject() failing_task = RunWithFailure(task, fail_n_times=2) for fname, run_operation in test_cases(RUN_OPERATION): with self.subTest(fx=fname): times_run = run_operation(failing_task) self.assertEqual(times_run, 3) self.assertEqual(task._times_called, 3)
def test_custom_parameters_and_exception_fails(self): """doesn't catch the right exception""" t = OperationObject() task = RunWithFailure(t, fail_n_times=4) for fname, run_with_custom_parameters in test_cases(CUSTOM_PARAMETERS): with self.subTest(fx=fname), self.assertRaises( ControlledException ): run_with_custom_parameters(task) self.assertEqual(t._times_called, 1)
def test_custom_exception_fails(self): """An unexpected (!= allowed) exception occurs ==> fail raising that exception.""" for sut_deco in self.decorators_to_test: @sut_deco(allowed_exceptions=(AttributeError,)) def test_run(task): return task.run() task = RunWithFailure( OperationObject(), fail_n_times=2, exception_cls=RuntimeError ) with self.subTest(decorator_tested=sut_deco, decorated=test_run): with self.assertRaises(RuntimeError): test_run(task)
def test_custom_parameters_and_exception_fails(self): """doesn't catch the right exception, with retry limits != default.""" for sut_deco in self.decorators_to_test: @sut_deco( retries_limit=4, allowed_exceptions=(ZeroDivisionError, AttributeError), ) def test_run(task): return task.run() task = RunWithFailure( OperationObject(), fail_n_times=4, exception_cls=RuntimeError ) with self.subTest(decorator_tested=sut_deco, decorated=test_run): with self.assertRaises(RuntimeError) as cm: test_run(task) self.assertEqual(str(cm.exception), "task failed 1 times")
def _test_task_calls_and_retries( self, fail_task_n_times: int, expected_times_run: int, expected_times_called: Optional[int] = None, exception_cls=ControlledException, **decorator_kwargs, ): """Generic test for the decorator under certain conditions Create a function, and apply each decorator to test, to it. Then verify the conditions hold with the values passed by parameter. """ for sut_deco in self.decorators_to_test: @sut_deco(**decorator_kwargs) def test_run(task): return task.run() original_task = OperationObject() failing_task = RunWithFailure( original_task, fail_n_times=fail_task_n_times, exception_cls=exception_cls, ) with self.subTest( decorator_tested=sut_deco, decorated=test_run, **decorator_kwargs, ): times_run = test_run(failing_task) self.assertEqual(times_run, expected_times_run) if expected_times_called: self.assertEqual( original_task._times_called, expected_times_called )
def test_fail_equal_retry_limit(self): """Retry = fail = 3, will fail""" task = OperationObject() failing_task = RunWithFailure(task, fail_n_times=3) with self.assertRaises(ControlledException): run_operation(failing_task)