def test_multi_exception_raised_on_exceed(self): # limit retries so this doesn't take 40 seconds retry_fixture = fixture.DBRetryErrorsFixture(max_retries=2) retry_fixture.setUp() e = exceptions.MultipleExceptions([ValueError(), db_exc.DBDeadlock()]) with testtools.ExpectedException(exceptions.MultipleExceptions): self._decorated_function(db_api.MAX_RETRIES + 1, e) retry_fixture.cleanUp()
def test__create_dvr_mac_address_retries_exceeded_retry_logic(self): # limit retries so test doesn't take 40 seconds retry_fixture = fixture.DBRetryErrorsFixture(max_retries=2) retry_fixture.setUp() non_unique_mac = tools.get_random_EUI() self._create_dvr_mac_entry('foo_host_1', non_unique_mac) with mock.patch.object(net, 'get_random_mac') as f: f.return_value = non_unique_mac self.assertRaises(lib_exc.HostMacAddressGenerationFailure, self.mixin._create_dvr_mac_address, self.ctx, "foo_host_2") retry_fixture.cleanUp()
def _test_db_exceptions_handled(self, method, mock_object, expect_retries): # NOTE(mpeterson): make retries faster so it doesn't take a lot. retry_fixture = lib_fixtures.DBRetryErrorsFixture( max_retries=RETRY_MAX, retry_interval=RETRY_INTERVAL) retry_fixture.setUp() # NOTE(mpeterson): this test is very verbose, disabling logging logging.disable(logging.CRITICAL) self.addCleanup(logging.disable, logging.NOTSET) exceptions = RETRIABLE_EXCEPTIONS r_method = getattr(method, '__wrapped__', method) r_method_args = p_util.getargspec(r_method).args args_number = len(r_method_args) - (2 if r_method_args[0] == 'self' else 1) mock_arg = mock.MagicMock(unsafe=True) # NOTE(mpeterson): workarounds for py3 compatibility and behavior # expected by particular functions mock_arg.__name__ = 'mock_arg' mock_arg.retry_count = 1 mock_arg.__ge__.return_value = True mock_arg.__gt__.return_value = True mock_arg.__le__.return_value = True mock_arg.__lt__.return_value = True args = (mock_arg, ) * args_number def _assertRaises(exceptions, method, context, *args, **kwargs): try: method(context, *args, **kwargs) except Exception as e: if not isinstance(e, exceptions): raise e # TODO(mpeterson): For now the check with session.is_active is # accepted, but when the enginefacade is the only accepted # pattern then it should be changed to check that a session is # attached to the context session = context.session if session.is_active and isinstance(e, _InnerException): self.assertTrue(getattr(e, '_RETRY_EXCEEDED', False)) return exc_names = (tuple(exc.__name__ for exc in exceptions) if hasattr( exceptions, '__iter__') else exceptions.__name__) self.fail('%s did not raise %s' % (method.__name__, exc_names)) try: raise _InnerException except _InnerException as e: _e = e expected_retries = RETRY_MAX if expect_retries else 0 # TODO(mpeterson): Make this an int when Py2 is no longer supported # and use the `nonlocal` directive retry_counter = [0] for exception in exceptions: def increase_retry_counter_and_except(*args, **kwargs): retry_counter[0] += 1 self.db_context.session.add(self.retry_tracker()) self.db_context.session.flush() raise exception(_e) mock_object.side_effect = increase_retry_counter_and_except _assertRaises((exception, _InnerException), method, self.db_context, *args) self.assertEqual(expected_retries, mock_object.call_count - 1) mock_object.reset_mock() retry_fixture.cleanUp() return retry_counter[0]
def _test_db_exceptions_handled(self, method, mock_object, receives_context, expect_retries): # NOTE(mpeterson): make retries faster so it doesn't take a lot. retry_fixture = lib_fixtures.DBRetryErrorsFixture( max_retries=RETRY_MAX, retry_interval=RETRY_INTERVAL) retry_fixture.setUp() # NOTE(mpeterson): this test is very verbose, disabling logging logging.disable(logging.CRITICAL) self.addCleanup(logging.disable, logging.NOTSET) exceptions = RETRIABLE_EXCEPTIONS r_method = getattr(method, '__wrapped__', method) r_method_args = p_util.getargspec(r_method).args args_number = len(r_method_args) - (2 if r_method_args[0] == 'self' else 1) mock_arg = mock.MagicMock(unsafe=True) # NOTE(mpeterson): workarounds for py3 compatibility and behavior # expected by particular functions mock_arg.__name__ = 'mock_arg' mock_arg.retry_count = 1 mock_arg.__ge__.return_value = True mock_arg.__gt__.return_value = True mock_arg.__le__.return_value = True mock_arg.__lt__.return_value = True args = (mock_arg, ) * args_number def _assertRaises(exceptions, method, *args, **kwargs): try: method(*args, **kwargs) except Exception as e: if not isinstance(e, exceptions): raise e session = args[0].session if receives_context else args[0] if session.is_active and isinstance(e, _InnerException): self.assertTrue(getattr(e, '_RETRY_EXCEEDED', False)) return exc_names = (tuple(exc.__name__ for exc in exceptions) if hasattr( exceptions, '__iter__') else exceptions.__name__) self.fail('%s did not raise %s' % (method.__name__, exc_names)) try: raise _InnerException except _InnerException as e: _e = e expected_retries = RETRY_MAX if expect_retries else 0 db_object = self.db_context if receives_context else self.db_session for exception in exceptions: mock_object.side_effect = exception(_e) _assertRaises((exception, _InnerException), method, db_object, *args) self.assertEqual(expected_retries, mock_object.call_count - 1) mock_object.reset_mock() retry_fixture.cleanUp()